diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd46b5..e7bcb5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ 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.5] - 2025-02-21 + +### Added + +- **Exact match option** – When enabled, the entire message must exactly match the trigger (e.g. `!` triggers only on messages that are just `!`, not `hello!`). + +### Fixed + +- **Cross-world friends for auto-accept** – Auto-accept now works when a friend invites you from another world or while visiting another world (fallback to name-only match when world ID differs). + ## [1.0.4] - 2025-02-20 ### Added diff --git a/HSRTools/Configuration/FriendFcCache.cs b/HSRTools/Configuration/FriendFcCache.cs index 93ad8da..50e82dd 100644 --- a/HSRTools/Configuration/FriendFcCache.cs +++ b/HSRTools/Configuration/FriendFcCache.cs @@ -24,6 +24,13 @@ public class FriendFcCache return Friends.Exists(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && p.WorldId == worldId); } + /// Name-only match for cross-world friends (e.g. friend visiting another world). + public bool IsInFriendsByName(string name) + { + if (Friends == null || Friends.Count == 0) return false; + return Friends.Exists(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + } + public bool IsInFreeCompany(string name, ushort worldId) { if (FreeCompanyMembers == null || FreeCompanyMembers.Count == 0) return false; diff --git a/HSRTools/Configuration/HSRToolsConfiguration.cs b/HSRTools/Configuration/HSRToolsConfiguration.cs index 9e11402..3169410 100644 --- a/HSRTools/Configuration/HSRToolsConfiguration.cs +++ b/HSRTools/Configuration/HSRToolsConfiguration.cs @@ -15,6 +15,12 @@ public class HSRToolsConfiguration /// public bool CaseSensitive { get; set; } = false; + /// + /// When true, the entire message must exactly match the trigger (after trimming). + /// When false, the message only needs to contain the trigger anywhere. + /// + public bool TriggerExactMatch { get; set; } = false; + /// /// Whether to monitor Free Company chat. /// diff --git a/HSRTools/HSRTools.csproj b/HSRTools/HSRTools.csproj index 3f15c14..8c3e1e3 100644 --- a/HSRTools/HSRTools.csproj +++ b/HSRTools/HSRTools.csproj @@ -1,7 +1,7 @@ true - 1.0.4.0 + 1.0.5.0 Knack117 HSRTools HSRTools diff --git a/HSRTools/Services/AutoAcceptPartyService.cs b/HSRTools/Services/AutoAcceptPartyService.cs index 422c3a2..d9eb3a5 100644 --- a/HSRTools/Services/AutoAcceptPartyService.cs +++ b/HSRTools/Services/AutoAcceptPartyService.cs @@ -126,7 +126,7 @@ public sealed class AutoAcceptPartyService if (_config.Debug) _log.Info($"[AutoAccept] Inviter: '{inviterName}' (worldId={inviterWorldId})"); - var isFriend = _config.AutoAcceptFromFriends && (IsFriendCached(inviterName, inviterWorldId) || IsFriend(inviterName, inviterWorldId)); + var isFriend = _config.AutoAcceptFromFriends && (IsFriendCached(inviterName, inviterWorldId) || IsFriend(inviterName, inviterWorldId) || IsFriendCachedByName(inviterName)); var isFcMember = _config.AutoAcceptFromFreeCompany && (IsFreeCompanyMemberCached(inviterName, inviterWorldId) || IsFreeCompanyMember(inviterName, inviterWorldId)); if (_config.Debug) @@ -159,6 +159,7 @@ public sealed class AutoAcceptPartyService } private bool IsFriendCached(string characterName, ushort worldId) => _cacheService.IsInFriends(characterName, worldId); + private bool IsFriendCachedByName(string characterName) => _cacheService.IsInFriendsByName(characterName); private bool IsFreeCompanyMemberCached(string characterName, ushort worldId) => _cacheService.IsInFreeCompany(characterName, worldId); private unsafe bool IsFriend(string characterName, ushort worldId) diff --git a/HSRTools/Services/ChatMonitorService.cs b/HSRTools/Services/ChatMonitorService.cs index efb40bc..b7b586e 100644 --- a/HSRTools/Services/ChatMonitorService.cs +++ b/HSRTools/Services/ChatMonitorService.cs @@ -150,8 +150,16 @@ public sealed class ChatMonitorService var trigger = _config.TriggerText; var comparison = _config.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; - if (!messageText.Contains(trigger, comparison)) - return; + if (_config.TriggerExactMatch) + { + if (!messageText.Trim().Equals(trigger, comparison)) + return; + } + else + { + if (!messageText.Contains(trigger, comparison)) + return; + } // Read log module first for non-tells (sender data only valid at callback start; overwritten quickly). var (logContentId, logWorldId) = type != XivChatType.TellIncoming diff --git a/HSRTools/Services/FriendFcCacheService.cs b/HSRTools/Services/FriendFcCacheService.cs index 120fd10..811fac9 100644 --- a/HSRTools/Services/FriendFcCacheService.cs +++ b/HSRTools/Services/FriendFcCacheService.cs @@ -86,6 +86,12 @@ public sealed class FriendFcCacheService lock (_cacheLock) { return _cache.IsInFriends(name, worldId); } } + /// Name-only match for cross-world friends (friend visiting another world). + public bool IsInFriendsByName(string name) + { + lock (_cacheLock) { return _cache.IsInFriendsByName(name); } + } + public bool IsInFreeCompany(string name, ushort worldId) { lock (_cacheLock) { return _cache.IsInFreeCompany(name, worldId); } diff --git a/HSRTools/UI/ConfigWindow.cs b/HSRTools/UI/ConfigWindow.cs index 208570a..3ec2b2b 100644 --- a/HSRTools/UI/ConfigWindow.cs +++ b/HSRTools/UI/ConfigWindow.cs @@ -9,6 +9,7 @@ public sealed class ConfigWindow : Window private readonly HSRToolsConfiguration _config; private string _triggerTextInput = string.Empty; private bool _caseSensitive; + private bool _triggerExactMatch; private bool _monitorFreeCompany; private bool _monitorLinkShell; private bool _monitorCrossWorldLinkShell; @@ -32,6 +33,7 @@ public sealed class ConfigWindow : Window { _triggerTextInput = _config.TriggerText ?? string.Empty; _caseSensitive = _config.CaseSensitive; + _triggerExactMatch = _config.TriggerExactMatch; _monitorFreeCompany = _config.MonitorFreeCompany; _monitorLinkShell = _config.MonitorLinkShell; _monitorCrossWorldLinkShell = _config.MonitorCrossWorldLinkShell; @@ -51,6 +53,7 @@ public sealed class ConfigWindow : Window { _config.TriggerText = "inv"; _config.CaseSensitive = false; + _config.TriggerExactMatch = false; _config.MonitorFreeCompany = true; _config.MonitorLinkShell = true; _config.MonitorCrossWorldLinkShell = true; @@ -74,8 +77,10 @@ public sealed class ConfigWindow : Window if (ImGui.InputText("##trigger", ref _triggerTextInput, 128)) _config.TriggerText = _triggerTextInput.Trim(); - ImGui.Checkbox("Case sensitive", ref _caseSensitive); - _config.CaseSensitive = _caseSensitive; + if (ImGui.Checkbox("Case sensitive", ref _caseSensitive)) + _config.CaseSensitive = _caseSensitive; + if (ImGui.Checkbox("Exact match (whole message must equal trigger)", ref _triggerExactMatch)) + _config.TriggerExactMatch = _triggerExactMatch; ImGui.Separator(); ImGui.Text("Monitor these channels:");