2 Commits

8 changed files with 49 additions and 6 deletions
+10
View File
@@ -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
+7
View File
@@ -24,6 +24,13 @@ public class FriendFcCache
return Friends.Exists(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && p.WorldId == worldId);
}
/// <summary>Name-only match for cross-world friends (e.g. friend visiting another world).</summary>
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;
@@ -15,6 +15,12 @@ public class HSRToolsConfiguration
/// </summary>
public bool CaseSensitive { get; set; } = false;
/// <summary>
/// When true, the entire message must exactly match the trigger (after trimming).
/// When false, the message only needs to contain the trigger anywhere.
/// </summary>
public bool TriggerExactMatch { get; set; } = false;
/// <summary>
/// Whether to monitor Free Company chat.
/// </summary>
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Dalamud.NET.Sdk/14.0.1">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.4.0</Version>
<Version>1.0.5.0</Version>
<Author>Knack117</Author>
<Name>HSRTools</Name>
<InternalName>HSRTools</InternalName>
+2 -1
View File
@@ -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)
+8
View File
@@ -150,8 +150,16 @@ public sealed class ChatMonitorService
var trigger = _config.TriggerText;
var comparison = _config.CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
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
@@ -86,6 +86,12 @@ public sealed class FriendFcCacheService
lock (_cacheLock) { return _cache.IsInFriends(name, worldId); }
}
/// <summary>Name-only match for cross-world friends (friend visiting another world).</summary>
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); }
+6 -1
View File
@@ -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);
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:");