From dc249b2cbb386398b6fc6d86c7ecd6967f2a5593 Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Thu, 6 Aug 2020 00:17:14 -0400 Subject: [PATCH] feat: add "advanced mode" with custom filters --- NoSoliciting/NoSoliciting.csproj | 3 +- NoSoliciting/PluginConfiguration.cs | 11 ++ NoSoliciting/PluginUI.cs | 149 +++++++++++++++++++++-- NoSoliciting/RMTDetection.Chat.cs | 24 +++- NoSoliciting/RMTDetection.PartyFinder.cs | 15 +++ NoSoliciting/RMTDetection.cs | 12 +- 6 files changed, 199 insertions(+), 15 deletions(-) diff --git a/NoSoliciting/NoSoliciting.csproj b/NoSoliciting/NoSoliciting.csproj index f35cb88..8eda878 100644 --- a/NoSoliciting/NoSoliciting.csproj +++ b/NoSoliciting/NoSoliciting.csproj @@ -55,6 +55,7 @@ + @@ -63,7 +64,6 @@ - @@ -73,6 +73,7 @@ + diff --git a/NoSoliciting/PluginConfiguration.cs b/NoSoliciting/PluginConfiguration.cs index 90a220f..67e839c 100644 --- a/NoSoliciting/PluginConfiguration.cs +++ b/NoSoliciting/PluginConfiguration.cs @@ -2,6 +2,7 @@ using Dalamud.Plugin; using Newtonsoft.Json; using System; +using System.Collections.Generic; namespace NoSoliciting { [Serializable] @@ -14,6 +15,16 @@ namespace NoSoliciting { public bool FilterChat { get; set; } = true; public bool FilterPartyFinder { get; set; } = true; + public bool AdvancedMode { get; set; } = false; + + public bool CustomChatFilter { get; set; } = false; + public List ChatSubstrings { get; } = new List(); + public List ChatRegexes { get; } = new List(); + + public bool CustomPFFilter { get; set; } = false; + public List PFSubstrings { get; } = new List(); + public List PFRegexes { get; } = new List(); + public void Initialise(DalamudPluginInterface pi) { this.pi = pi ?? throw new ArgumentNullException(nameof(pi), "DalamudPluginInterface cannot be null"); } diff --git a/NoSoliciting/PluginUI.cs b/NoSoliciting/PluginUI.cs index 7faf520..932aaec 100644 --- a/NoSoliciting/PluginUI.cs +++ b/NoSoliciting/PluginUI.cs @@ -1,5 +1,8 @@ using ImGuiNET; using System; +using System.Collections.Generic; +using System.Numerics; +using System.Text.RegularExpressions; namespace NoSoliciting { public class PluginUI { @@ -24,20 +27,152 @@ namespace NoSoliciting { public void DrawSettings() { if (ImGui.Begin($"{this.plugin.Name} settings", ref this._showSettings)) { - bool filterChat = this.plugin.Config.FilterChat; - if (ImGui.Checkbox("Filter RMT from chat", ref filterChat)) { - this.plugin.Config.FilterChat = filterChat; - this.plugin.Config.Save(); + if (this.plugin.Config.AdvancedMode) { + this.DrawAdvancedSettings(); + } else { + this.DrawBasicSettings(); } - bool filterPartyFinder = this.plugin.Config.FilterPartyFinder; - if (ImGui.Checkbox("Filter RMT from Party Finder", ref filterPartyFinder)) { - this.plugin.Config.FilterPartyFinder = filterPartyFinder; + ImGui.Separator(); + + bool advanced = this.plugin.Config.AdvancedMode; + if (ImGui.Checkbox("Advanced mode", ref advanced)) { + this.plugin.Config.AdvancedMode = advanced; this.plugin.Config.Save(); } ImGui.End(); } } + + private void DrawBasicSettings() { + ImGui.SetWindowSize(new Vector2(225, 125)); + + bool filterChat = this.plugin.Config.FilterChat; + if (ImGui.Checkbox("Filter RMT from chat", ref filterChat)) { + this.plugin.Config.FilterChat = filterChat; + this.plugin.Config.Save(); + } + + bool filterPartyFinder = this.plugin.Config.FilterPartyFinder; + if (ImGui.Checkbox("Filter RMT from Party Finder", ref filterPartyFinder)) { + this.plugin.Config.FilterPartyFinder = filterPartyFinder; + this.plugin.Config.Save(); + } + } + + private void DrawAdvancedSettings() { + ImGui.SetWindowSize(new Vector2(600, 400)); + + if (ImGui.BeginTabBar("##nosoliciting-tabs")) { + if (ImGui.BeginTabItem("Chat")) { + bool filterChat = this.plugin.Config.FilterChat; + if (ImGui.Checkbox("Enable built-in RMT filter", ref filterChat)) { + this.plugin.Config.FilterChat = filterChat; + this.plugin.Config.Save(); + } + + bool customChat = this.plugin.Config.CustomChatFilter; + if (ImGui.Checkbox("Enable custom chat filters", ref customChat)) { + this.plugin.Config.CustomChatFilter = customChat; + this.plugin.Config.Save(); + } + + if (this.plugin.Config.CustomChatFilter) { + List substrings = this.plugin.Config.ChatSubstrings; + List regexes = this.plugin.Config.ChatRegexes; + this.DrawCustom("chat", ref substrings, ref regexes); + } + + ImGui.EndTabItem(); + } + + if (ImGui.BeginTabItem("Party Finder")) { + bool filterPartyFinder = this.plugin.Config.FilterPartyFinder; + if (ImGui.Checkbox("Enable built-in Party Finder RMT filter", ref filterPartyFinder)) { + this.plugin.Config.FilterPartyFinder = filterPartyFinder; + this.plugin.Config.Save(); + } + + bool customPF = this.plugin.Config.CustomPFFilter; + if (ImGui.Checkbox("Enable custom Party Finder filters", ref customPF)) { + this.plugin.Config.CustomPFFilter = customPF; + this.plugin.Config.Save(); + } + + if (this.plugin.Config.CustomPFFilter) { + List substrings = this.plugin.Config.PFSubstrings; + List regexes = this.plugin.Config.PFRegexes; + this.DrawCustom("pf", ref substrings, ref regexes); + } + + ImGui.EndTabItem(); + } + + ImGui.EndTabBar(); + } + } + + private void DrawCustom(string name, ref List substrings, ref List regexes) { + ImGui.Columns(2); + + ImGui.Text("Substrings to filter"); + if (ImGui.BeginChild($"##{name}-substrings", new Vector2(0, 175))) { + for (int i = 0; i < substrings.Count; i++) { + string input = substrings[i]; + if (ImGui.InputText($"##{name}-substring-{i}", ref input, 100)) { + if (input.Length != 0) { + substrings[i] = input; + } + } + ImGui.SameLine(); + if (ImGui.Button($"Remove##{name}-substring-{i}-remove")) { + substrings.RemoveAt(i); + } + } + + if (ImGui.Button($"Add##{name}-substring-add")) { + substrings.Add(""); + } + + ImGui.EndChild(); + } + + ImGui.NextColumn(); + + ImGui.Text("Regular expressions to filter"); + if (ImGui.BeginChild($"##{name}-regexes", new Vector2(0, 175))) { + for (int i = 0; i < regexes.Count; i++) { + string input = regexes[i]; + if (ImGui.InputText($"##{name}-regex-{i}", ref input, 100)) { + bool valid = true; + try { + _ = new Regex(input); + } catch (ArgumentException) { + valid = false; + } + if (valid && input.Length != 0) { + regexes[i] = input; + } + } + ImGui.SameLine(); + if (ImGui.Button($"Remove##{name}-regex-{i}-remove")) { + regexes.RemoveAt(i); + } + } + + if (ImGui.Button($"Add##{name}-regex-add")) { + regexes.Add(""); + } + + ImGui.EndChild(); + } + + ImGui.Columns(1); + + if (ImGui.Button($"Save filters##{name}-save")) { + this.plugin.Config.Save(); + } + } } } diff --git a/NoSoliciting/RMTDetection.Chat.cs b/NoSoliciting/RMTDetection.Chat.cs index 8baf94a..7a77300 100644 --- a/NoSoliciting/RMTDetection.Chat.cs +++ b/NoSoliciting/RMTDetection.Chat.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Text.RegularExpressions; namespace NoSoliciting { @@ -34,13 +35,30 @@ namespace NoSoliciting { "使用する5%オ", "offers Fantasia", }; - private static readonly Regex rmtRegex = new Regex(@"Off Code( *)", RegexOptions.Compiled); + private static readonly Regex[] rmtRegexes = { + new Regex(@"Off Code( *)", RegexOptions.Compiled), + }; public static bool IsRMT(string msg) { msg = RMTUtil.Normalise(msg); return rmtSubstrings.Any(needle => msg.Contains(needle)) - || rmtRegex.IsMatch(msg); + || rmtRegexes.Any(needle => needle.IsMatch(msg)); + } + + public static bool MatchesCustomFilters(string msg, PluginConfiguration config) { + if (config == null) { + throw new ArgumentNullException(nameof(config), "PluginConfiguration cannot be null"); + } + + if (!config.AdvancedMode || !config.CustomChatFilter) { + return false; + } + + msg = RMTUtil.Normalise(msg); + + return config.ChatSubstrings.Any(needle => msg.Contains(needle)) + || config.ChatRegexes.Any(needle => Regex.IsMatch(msg, needle)); } } } diff --git a/NoSoliciting/RMTDetection.PartyFinder.cs b/NoSoliciting/RMTDetection.PartyFinder.cs index f757380..79da046 100644 --- a/NoSoliciting/RMTDetection.PartyFinder.cs +++ b/NoSoliciting/RMTDetection.PartyFinder.cs @@ -33,6 +33,21 @@ namespace NoSoliciting { return containsSell && containsDiscordTag && containsContent; } + + public static bool MatchesCustomFilters(string msg, PluginConfiguration config) { + if (config == null) { + throw new ArgumentNullException(nameof(config), "PluginConfiguration cannot be null"); + } + + if (!config.AdvancedMode || !config.CustomPFFilter) { + return false; + } + + msg = RMTUtil.Normalise(msg); + + return config.PFSubstrings.Any(needle => msg.Contains(needle)) + || config.PFRegexes.Any(needle => Regex.IsMatch(msg, needle)); + } } } } diff --git a/NoSoliciting/RMTDetection.cs b/NoSoliciting/RMTDetection.cs index 7281f8e..be81bfe 100644 --- a/NoSoliciting/RMTDetection.cs +++ b/NoSoliciting/RMTDetection.cs @@ -37,8 +37,10 @@ namespace NoSoliciting { continue; } + string desc = listing.Description(); + // only look at listings that are RMT - if (!PartyFinder.IsRMT(listing.Description())) { + if (!PartyFinder.IsRMT(desc) && !PartyFinder.MatchesCustomFilters(desc, this.plugin.Config)) { continue; } @@ -76,10 +78,12 @@ namespace NoSoliciting { string text = message.TextValue; - if (Chat.IsRMT(text)) { - PluginLog.Log($"Handled RMT message: {text}"); - isHandled = true; + if (!Chat.IsRMT(text) && !Chat.MatchesCustomFilters(text, this.plugin.Config)) { + return; } + + PluginLog.Log($"Handled RMT message: {text}"); + isHandled = true; } } }