diff --git a/CHANGELOG.md b/CHANGELOG.md
index de33be6..8cd46b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [1.0.4] - 2025-02-20
+
+### Added
+
+- **Auto-accept party invites** – Option to automatically accept party invites when the inviter is on your friend list or is a member of your Free Company. Configurable toggles for friends and FC members.
+
## [1.0.3] - 2025-02-03
### Added
diff --git a/HSRTools/Configuration/HSRToolsConfiguration.cs b/HSRTools/Configuration/HSRToolsConfiguration.cs
index 9163db7..b3da551 100644
--- a/HSRTools/Configuration/HSRToolsConfiguration.cs
+++ b/HSRTools/Configuration/HSRToolsConfiguration.cs
@@ -45,4 +45,22 @@ public class HSRToolsConfiguration
/// Use this to diagnose cross-world invite issues.
///
public bool Debug { get; set; } = false;
+
+ // --- Auto-accept party invites ---
+
+ ///
+ /// When true, automatically accept party invites from friends and/or Free Company members
+ /// (based on the options below).
+ ///
+ public bool AutoAcceptEnabled { get; set; } = false;
+
+ ///
+ /// When true and AutoAcceptEnabled, accept party invites from players on your friend list.
+ ///
+ public bool AutoAcceptFromFriends { get; set; } = true;
+
+ ///
+ /// When true and AutoAcceptEnabled, accept party invites from members of your Free Company.
+ ///
+ public bool AutoAcceptFromFreeCompany { get; set; } = true;
}
diff --git a/HSRTools/HSRTools.csproj b/HSRTools/HSRTools.csproj
index 792d55c..3f15c14 100644
--- a/HSRTools/HSRTools.csproj
+++ b/HSRTools/HSRTools.csproj
@@ -1,7 +1,7 @@
true
- 1.0.3.0
+ 1.0.4.0
Knack117
HSRTools
HSRTools
diff --git a/HSRTools/HSRTools.json b/HSRTools/HSRTools.json
index 3f3fba9..c6d1401 100644
--- a/HSRTools/HSRTools.json
+++ b/HSRTools/HSRTools.json
@@ -1,8 +1,8 @@
{
"Author": "Knack117",
"Name": "HSRTools",
- "Punchline": "Auto-invite to party when a trigger word is said in FC, LS, CWLS, or tells.",
- "Description": "Detects a user-defined trigger word in Free Company, Link Shell, Cross-World Link Shell, and tell chat, then invites the sender to your party. Works for same-world and cross-world (CWLS).",
+ "Punchline": "Auto-invite and auto-accept party invites from friends/FC.",
+ "Description": "Detects a trigger word in FC, LS, CWLS, and tells to auto-invite; optionally auto-accepts party invites from friends and FC members.",
"RepoUrl": "https://github.com/Knack117/HSRTools",
"Tags": [ "chat", "party", "invite", "automation" ],
"AcceptsFeedback": true
diff --git a/HSRTools/Plugin.cs b/HSRTools/Plugin.cs
index d38f515..a6cc6e2 100644
--- a/HSRTools/Plugin.cs
+++ b/HSRTools/Plugin.cs
@@ -15,6 +15,7 @@ public sealed class HSRToolsPlugin : IDalamudPlugin
private readonly string _configDir;
private readonly ChatMonitorService _chatMonitorService;
+ private readonly AutoAcceptPartyService _autoAcceptPartyService;
private readonly ConfigWindow _configWindow;
private readonly WindowSystem _windowSystem;
private HSRToolsConfiguration _config;
@@ -32,6 +33,11 @@ public sealed class HSRToolsPlugin : IDalamudPlugin
PluginServices.PluginLog,
_config);
+ _autoAcceptPartyService = new AutoAcceptPartyService(
+ PluginServices.AddonLifecycle,
+ PluginServices.PluginLog,
+ _config);
+
_configWindow = new ConfigWindow(_config);
_windowSystem = new WindowSystem("HSRTools");
_windowSystem.AddWindow(_configWindow);
@@ -44,12 +50,15 @@ public sealed class HSRToolsPlugin : IDalamudPlugin
});
_chatMonitorService.SetConfiguration(_config);
_chatMonitorService.Start();
+ _autoAcceptPartyService.SetConfiguration(_config);
+ _autoAcceptPartyService.Start();
}
public void Dispose()
{
PluginServices.CommandManager.RemoveHandler("/hsr");
_chatMonitorService.Stop();
+ _autoAcceptPartyService.Stop();
_windowSystem.RemoveAllWindows();
SaveConfig(_configDir, _config);
}
diff --git a/HSRTools/Services/AutoAcceptPartyService.cs b/HSRTools/Services/AutoAcceptPartyService.cs
new file mode 100644
index 0000000..9fc82d9
--- /dev/null
+++ b/HSRTools/Services/AutoAcceptPartyService.cs
@@ -0,0 +1,134 @@
+using System;
+using Dalamud.Game.Addon.Lifecycle;
+using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
+using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.UI.Agent;
+using FFXIVClientStructs.FFXIV.Client.UI.Info;
+using HSRTools.Configuration;
+
+namespace HSRTools.Services;
+
+///
+/// Automatically accepts party invites when the inviter is a friend or Free Company member.
+/// Uses IAddonLifecycle to detect when the party invite addon opens, then checks the
+/// inviter against the friend list and FC roster before accepting.
+///
+public sealed class AutoAcceptPartyService
+{
+ private const string PartyInviteAddonName = "PartyInvite";
+
+ private readonly IAddonLifecycle _addonLifecycle;
+ private readonly IPluginLog _log;
+ private HSRToolsConfiguration _config;
+
+ public AutoAcceptPartyService(IAddonLifecycle addonLifecycle, IPluginLog log, HSRToolsConfiguration config)
+ {
+ _addonLifecycle = addonLifecycle;
+ _log = log;
+ _config = config;
+ }
+
+ public void SetConfiguration(HSRToolsConfiguration config)
+ {
+ _config = config;
+ }
+
+ public void Start()
+ {
+ _addonLifecycle.RegisterListener(AddonEvent.PreSetup, PartyInviteAddonName, OnPartyInviteAddon);
+ }
+
+ public void Stop()
+ {
+ _addonLifecycle.UnregisterListener(AddonEvent.PreSetup, PartyInviteAddonName, OnPartyInviteAddon);
+ }
+
+ private void OnPartyInviteAddon(AddonEvent eventType, AddonArgs args)
+ {
+ if (!_config.AutoAcceptEnabled)
+ return;
+
+ if (!_config.AutoAcceptFromFriends && !_config.AutoAcceptFromFreeCompany)
+ return;
+
+ unsafe
+ {
+ var agent = AgentPartyInvite.Instance();
+ if (agent == null)
+ return;
+
+ var proxy = agent->InfoProxyPartyInvite;
+ if (proxy == null)
+ return;
+
+ var inviterName = proxy->InviterName.ToString();
+ if (string.IsNullOrWhiteSpace(inviterName))
+ return;
+
+ var inviterWorldId = proxy->InviterWorldId;
+
+ var isFriend = _config.AutoAcceptFromFriends && IsFriend(inviterName, inviterWorldId);
+ var isFcMember = _config.AutoAcceptFromFreeCompany && IsFreeCompanyMember(inviterName, inviterWorldId);
+
+ if (!isFriend && !isFcMember)
+ return;
+
+ var reason = isFriend && isFcMember ? "friend and FC member" : isFriend ? "friend" : "FC member";
+ _log.Info($"Auto-accepting party invite from {inviterName} ({reason}).");
+
+ try
+ {
+ // RespondToInvitation is on InfoProxyInvitedList (parent of InfoProxyPartyInvite)
+ var accepted = ((InfoProxyInvitedList*)proxy)->RespondToInvitation(inviterName, true);
+ if (!accepted)
+ _log.Warning($"Failed to auto-accept party invite from {inviterName}.");
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex, $"Error auto-accepting party invite from {inviterName}");
+ }
+ }
+ }
+
+ private static unsafe bool IsFriend(string characterName, ushort worldId)
+ {
+ try
+ {
+ var infoModule = InfoModule.Instance();
+ if (infoModule == null)
+ return false;
+
+ var proxy = (InfoProxyCommonList*)infoModule->GetInfoProxyById(InfoProxyId.FriendList);
+ if (proxy == null)
+ return false;
+
+ var entry = proxy->GetEntryByName(characterName, worldId);
+ return entry != null;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ private static unsafe bool IsFreeCompanyMember(string characterName, ushort worldId)
+ {
+ try
+ {
+ var infoModule = InfoModule.Instance();
+ if (infoModule == null)
+ return false;
+
+ var proxy = (InfoProxyCommonList*)infoModule->GetInfoProxyById(InfoProxyId.FreeCompanyMember);
+ if (proxy == null)
+ return false;
+
+ var entry = proxy->GetEntryByName(characterName, worldId);
+ return entry != null;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+}
diff --git a/HSRTools/Services/PluginServices.cs b/HSRTools/Services/PluginServices.cs
index 679604b..dc4bd83 100644
--- a/HSRTools/Services/PluginServices.cs
+++ b/HSRTools/Services/PluginServices.cs
@@ -13,4 +13,5 @@ public sealed class PluginServices
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
[PluginService] public static IToastGui ToastGui { get; private set; } = null!;
[PluginService] public static ICommandManager CommandManager { get; private set; } = null!;
+ [PluginService] public static IAddonLifecycle AddonLifecycle { get; private set; } = null!;
}
diff --git a/HSRTools/UI/ConfigWindow.cs b/HSRTools/UI/ConfigWindow.cs
index 10fb357..527302d 100644
--- a/HSRTools/UI/ConfigWindow.cs
+++ b/HSRTools/UI/ConfigWindow.cs
@@ -15,6 +15,9 @@ public sealed class ConfigWindow : Window
private bool _monitorTell;
private bool _enabled;
private bool _debug;
+ private bool _autoAcceptEnabled;
+ private bool _autoAcceptFromFriends;
+ private bool _autoAcceptFromFreeCompany;
public ConfigWindow(HSRToolsConfiguration config)
: base("HSRTools Configuration", ImGuiWindowFlags.AlwaysAutoResize)
@@ -33,6 +36,9 @@ public sealed class ConfigWindow : Window
_monitorTell = _config.MonitorTell;
_enabled = _config.Enabled;
_debug = _config.Debug;
+ _autoAcceptEnabled = _config.AutoAcceptEnabled;
+ _autoAcceptFromFriends = _config.AutoAcceptFromFriends;
+ _autoAcceptFromFreeCompany = _config.AutoAcceptFromFreeCompany;
}
public override void Draw()
@@ -47,6 +53,9 @@ public sealed class ConfigWindow : Window
_config.MonitorTell = true;
_config.Enabled = true;
_config.Debug = false;
+ _config.AutoAcceptEnabled = false;
+ _config.AutoAcceptFromFriends = true;
+ _config.AutoAcceptFromFreeCompany = true;
SyncFromConfig();
}
@@ -78,5 +87,19 @@ public sealed class ConfigWindow : Window
ImGui.Separator();
if (ImGui.Checkbox("Debug logging (diagnose cross-world invite)", ref _debug))
_config.Debug = _debug;
+
+ ImGui.Separator();
+ ImGui.Text("Auto-accept party invites:");
+ ImGui.Indent();
+ if (ImGui.Checkbox("Auto-accept from friends and FC members", ref _autoAcceptEnabled))
+ _config.AutoAcceptEnabled = _autoAcceptEnabled;
+ if (_autoAcceptEnabled)
+ {
+ if (ImGui.Checkbox(" From friends", ref _autoAcceptFromFriends))
+ _config.AutoAcceptFromFriends = _autoAcceptFromFriends;
+ if (ImGui.Checkbox(" From Free Company members", ref _autoAcceptFromFreeCompany))
+ _config.AutoAcceptFromFreeCompany = _autoAcceptFromFreeCompany;
+ }
+ ImGui.Unindent();
}
}
diff --git a/README.md b/README.md
index cd6649a..7216497 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@ A [Dalamud](https://github.com/goatcorp/Dalamud) plugin for FFXIV (XIVLauncher)
## Features
- **Configurable trigger text** – Set any word or phrase (e.g. `inv`, `invite`, `party`). When someone types it in a monitored channel, they are invited to your party.
+- **Auto-accept party invites** – Optionally automatically accept party invites when the inviter is on your friend list or is a member of your Free Company.
- **Channel selection** – Choose which channels to monitor:
- Free Company
- Link Shell (1–8)
@@ -21,6 +22,10 @@ A [Dalamud](https://github.com/goatcorp/Dalamud) plugin for FFXIV (XIVLauncher)
For **tells**, the game provides the sender’s content ID and world, so invites work reliably. For **FC, LS, and CWLS**, the plugin uses the sender’s content ID when available (e.g. from the last message in CWLS), so cross-world invites work for CWLS and same-world for FC/LS.
+### Auto-accept party invites
+
+When enabled, the plugin detects incoming party invites and automatically accepts them if the inviter is on your friend list or is a member of your Free Company. You can toggle friends and FC members independently. The friend list and FC roster must have been opened in-game at least once for the plugin to recognize members.
+
## Building
1. Open `HSRTools.sln` in Visual Studio or use the command line.
@@ -35,7 +40,7 @@ For **tells**, the game provides the sender’s content ID and world, so invites
## Configuration
- Open the plugin config from the Dalamud plugin list (right-click HSRTools → **Settings**).
-- Set the trigger text, enable/disable the plugin, choose channels, and set case sensitivity.
+- Set the trigger text, enable/disable the plugin, choose channels, set case sensitivity, and configure auto-accept (friends/FC).
- Settings are saved when you close the game or disable the plugin.
## Requirements