From 04589e00a3cd83325d98ee0b5116280e161b9e5c Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Tue, 24 Aug 2021 14:18:09 -0400 Subject: [PATCH] refactor: move to net5 --- SoundFilter/Commands.cs | 27 ++++++--- SoundFilter/Config/Migrator.cs | 12 ++-- SoundFilter/Filter.cs | 32 +++++++--- SoundFilter/FodyWeavers.xml | 2 - SoundFilter/PluginShim.cs | 18 ------ SoundFilter/SoundFilter.csproj | 13 ++-- SoundFilter/SoundFilter.yaml | 4 ++ SoundFilter/SoundFilterPlugin.cs | 46 ++++++++++----- SoundFilter/Ui/PluginUi.cs | 11 ++-- SoundFilter/Ui/Settings.cs | 8 +-- SoundFilter/Util.cs | 1 - icon.png | Bin 0 -> 7240 bytes icon.svg | 98 +++++++++++++++++++++++++++++++ 13 files changed, 198 insertions(+), 74 deletions(-) delete mode 100755 SoundFilter/PluginShim.cs create mode 100644 icon.png create mode 100755 icon.svg diff --git a/SoundFilter/Commands.cs b/SoundFilter/Commands.cs index 3e5002e..de3f55e 100755 --- a/SoundFilter/Commands.cs +++ b/SoundFilter/Commands.cs @@ -12,13 +12,13 @@ namespace SoundFilter { public Commands(SoundFilterPlugin plugin) { this.Plugin = plugin; - this.Plugin.Interface.CommandManager.AddHandler(Name, new CommandInfo(this.OnCommand) { - HelpMessage = $"Toggle the {SoundFilterPlugin.Name} config", + this.Plugin.CommandManager.AddHandler(Name, new CommandInfo(this.OnCommand) { + HelpMessage = $"Toggle the {this.Plugin.Name} config", }); } public void Dispose() { - this.Plugin.Interface.CommandManager.RemoveHandler(Name); + this.Plugin.CommandManager.RemoveHandler(Name); } private void OnCommand(string command, string args) { @@ -27,13 +27,13 @@ namespace SoundFilter { return; } - var chat = this.Plugin.Interface.Framework.Gui.Chat; + var chat = this.Plugin.ChatGui; var split = args.Split(' '); if (split.Length < 1) { - chat.PrintError($"[{SoundFilterPlugin.Name}] {Language.CommandNotEnoughArguments}"); - chat.PrintError($"[{SoundFilterPlugin.Name}] /soundfilter log"); - chat.PrintError($"[{SoundFilterPlugin.Name}] /soundfilter [filter name]"); + chat.PrintError($"[{this.Plugin.Name}] {Language.CommandNotEnoughArguments}"); + chat.PrintError($"[{this.Plugin.Name}] /soundfilter log"); + chat.PrintError($"[{this.Plugin.Name}] /soundfilter [filter name]"); return; } @@ -46,7 +46,7 @@ namespace SoundFilter { var filterName = split.Length > 1 ? string.Join(" ", split.Skip(1)) : null; var filter = filterName == null ? null : this.Plugin.Config.Filters.FirstOrDefault(filter => filter.Name == filterName); if (filterName != null && filter == null) { - chat.PrintError($"[{SoundFilterPlugin.Name}] {Language.CommandNoSuchFilter}"); + chat.PrintError($"[{this.Plugin.Name}] {Language.CommandNoSuchFilter}"); return; } @@ -58,13 +58,22 @@ namespace SoundFilter { _ => null, }; if (enabled == null) { - chat.PrintError($"[{SoundFilterPlugin.Name}] {Language.CommandInvalidSubcommand}"); + chat.PrintError($"[{this.Plugin.Name}] {Language.CommandInvalidSubcommand}"); return; } if (filter != null) { filter.Enabled = enabled.Value; } else { + switch (this.Plugin.Config.Enabled) { + case true when !enabled.Value: + this.Plugin.Filter.Disable(); + break; + case false when enabled.Value: + this.Plugin.Filter.Enable(); + break; + } + this.Plugin.Config.Enabled = enabled.Value; } diff --git a/SoundFilter/Config/Migrator.cs b/SoundFilter/Config/Migrator.cs index 9814b72..2884a6f 100755 --- a/SoundFilter/Config/Migrator.cs +++ b/SoundFilter/Config/Migrator.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -using Dalamud.Plugin; +using Dalamud.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -22,9 +22,9 @@ namespace SoundFilter.Config { private static void MigrateV1(JObject old) { var filters = new List(); - WithEachObject(old["Filtered"], (glob, filter) => { - var name = filter["Name"].Value(); - var enabled = filter["Enabled"].Value(); + WithEachObject(old["Filtered"]!, (glob, filter) => { + var name = filter["Name"]!.Value()!; + var enabled = filter["Enabled"]!.Value(); filters.Add(new CustomFilter { Name = name, Enabled = enabled, @@ -48,7 +48,7 @@ namespace SoundFilter.Config { goto DefaultConfiguration; } - var config = JsonConvert.DeserializeObject(text); + var config = JsonConvert.DeserializeObject(text)!; int GetVersion() { if (config.TryGetValue("Version", out var token)) { @@ -78,7 +78,7 @@ namespace SoundFilter.Config { } if (version == Configuration.LatestVersion) { - return config.ToObject(); + return config.ToObject()!; } DefaultConfiguration: diff --git a/SoundFilter/Filter.cs b/SoundFilter/Filter.cs index 4c4a914..63de32a 100755 --- a/SoundFilter/Filter.cs +++ b/SoundFilter/Filter.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using Dalamud.Hooking; -using Dalamud.Plugin; +using Dalamud.Logging; namespace SoundFilter { internal unsafe class Filter : IDisposable { @@ -56,13 +56,13 @@ namespace SoundFilter { private IntPtr MusicManager { get { - if (!this.Plugin.Interface.TargetModuleScanner.TryScanText(Signatures.MusicManagerOffset, out var instructionPtr)) { + if (!this.Plugin.SigScanner.TryScanText(Signatures.MusicManagerOffset, out var instructionPtr)) { PluginLog.LogWarning("Could not find music manager"); return IntPtr.Zero; } var offset = *(int*) (instructionPtr + 3); - return *(IntPtr*) (this.Plugin.Interface.Framework.Address.BaseAddress + offset); + return *(IntPtr*) (this.Plugin.Framework.Address.BaseAddress + offset); } } @@ -126,16 +126,16 @@ namespace SoundFilter { } internal void Enable() { - if (this.PlaySpecificSoundHook == null && this.Plugin.Interface.TargetModuleScanner.TryScanText(Signatures.PlaySpecificSound, out var playPtr)) { - this.PlaySpecificSoundHook = new Hook(playPtr, new PlaySpecificSoundDelegate(this.PlaySpecificSoundDetour)); + if (this.PlaySpecificSoundHook == null && this.Plugin.SigScanner.TryScanText(Signatures.PlaySpecificSound, out var playPtr)) { + this.PlaySpecificSoundHook = new Hook(playPtr, this.PlaySpecificSoundDetour); } - if (this.GetResourceSyncHook == null && this.Plugin.Interface.TargetModuleScanner.TryScanText(Signatures.GetResourceSync, out var syncPtr)) { - this.GetResourceSyncHook = new Hook(syncPtr, new GetResourceSyncPrototype(this.GetResourceSyncDetour)); + if (this.GetResourceSyncHook == null && this.Plugin.SigScanner.TryScanText(Signatures.GetResourceSync, out var syncPtr)) { + this.GetResourceSyncHook = new Hook(syncPtr, this.GetResourceSyncDetour); } - if (this.GetResourceAsyncHook == null && this.Plugin.Interface.TargetModuleScanner.TryScanText(Signatures.GetResourceAsync, out var asyncPtr)) { - this.GetResourceAsyncHook = new Hook(asyncPtr, new GetResourceAsyncPrototype(this.GetResourceAsyncDetour)); + if (this.GetResourceAsyncHook == null && this.Plugin.SigScanner.TryScanText(Signatures.GetResourceAsync, out var asyncPtr)) { + this.GetResourceAsyncHook = new Hook(asyncPtr, this.GetResourceAsyncDetour); } this.PlaySpecificSoundHook?.Enable(); @@ -149,6 +149,20 @@ namespace SoundFilter { this.GetResourceAsyncHook?.Disable(); } + internal void Toggle(bool save = true) { + if (this.Plugin.Config.Enabled) { + this.Disable(); + } else { + this.Enable(); + } + + this.Plugin.Config.Enabled ^= true; + + if (save) { + this.Plugin.Config.Save(); + } + } + public void Dispose() { this.PlaySpecificSoundHook?.Dispose(); this.GetResourceSyncHook?.Dispose(); diff --git a/SoundFilter/FodyWeavers.xml b/SoundFilter/FodyWeavers.xml index 0609f45..37de851 100755 --- a/SoundFilter/FodyWeavers.xml +++ b/SoundFilter/FodyWeavers.xml @@ -1,5 +1,3 @@  - - diff --git a/SoundFilter/PluginShim.cs b/SoundFilter/PluginShim.cs deleted file mode 100755 index cbc8bfa..0000000 --- a/SoundFilter/PluginShim.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Dalamud.Plugin; - -namespace SoundFilter { - // ReSharper disable once UnusedType.Global - public class PluginShim : IDalamudPlugin { - public string Name => SoundFilterPlugin.Name; - - private SoundFilterPlugin? Plugin { get; set; } - - public void Initialize(DalamudPluginInterface pluginInterface) { - this.Plugin = new SoundFilterPlugin(pluginInterface); - } - - public void Dispose() { - this.Plugin?.Dispose(); - } - } -} diff --git a/SoundFilter/SoundFilter.csproj b/SoundFilter/SoundFilter.csproj index 54e56f1..784e878 100755 --- a/SoundFilter/SoundFilter.csproj +++ b/SoundFilter/SoundFilter.csproj @@ -1,10 +1,12 @@ - net48 + net5-windows 1.4.2 latest enable true + false + true @@ -39,11 +41,12 @@ - + - - + - + + + diff --git a/SoundFilter/SoundFilter.yaml b/SoundFilter/SoundFilter.yaml index 5eee63f..480b9d3 100755 --- a/SoundFilter/SoundFilter.yaml +++ b/SoundFilter/SoundFilter.yaml @@ -1,9 +1,13 @@ name: Sound Filter author: ascclemens +punchline: Filter any game sound. description: |- Filters any sound or set of sounds from the game. - Remove a battle sound effect you don't like - Remove specific emote sounds - Remove specific background music + + Icons: filter by Kirby Wu from the Noun Project + and Sound by Gregor Cresnar from the Noun Project repo_url: https://git.sr.ht/jkcclemens/SoundFilter diff --git a/SoundFilter/SoundFilterPlugin.cs b/SoundFilter/SoundFilterPlugin.cs index 4108f27..f071575 100755 --- a/SoundFilter/SoundFilterPlugin.cs +++ b/SoundFilter/SoundFilterPlugin.cs @@ -1,25 +1,41 @@ -using System; +using Dalamud.Game; +using Dalamud.Game.Command; +using Dalamud.Game.Gui; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; +using Dalamud.IoC; using Dalamud.Plugin; using SoundFilter.Config; using SoundFilter.Resources; using SoundFilter.Ui; namespace SoundFilter { - internal class SoundFilterPlugin : IDisposable { - internal const string Name = "Sound Filter"; + // ReSharper disable once ClassNeverInstantiated.Global + internal class SoundFilterPlugin : IDalamudPlugin { + public string Name => "Sound Filter"; + + [PluginService] + internal DalamudPluginInterface Interface { get; init; } = null!; + + [PluginService] + internal ChatGui ChatGui { get; init; } = null!; + + [PluginService] + internal CommandManager CommandManager { get; init; } = null!; + + [PluginService] + internal Framework Framework { get; init; } = null!; + + [PluginService] + internal SigScanner SigScanner { get; init; } = null!; - internal DalamudPluginInterface Interface { get; } internal Configuration Config { get; } internal Filter Filter { get; } internal PluginUi Ui { get; } private Commands Commands { get; } - internal SoundFilterPlugin(DalamudPluginInterface @interface) { - this.Interface = @interface; - + public SoundFilterPlugin() { this.Config = Migrator.LoadConfiguration(this); this.Config.Initialise(this.Interface); @@ -35,14 +51,14 @@ namespace SoundFilter { return; } - var message = string.Format(Language.LoadWarning, Name); - this.Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry { - Name = Name, - MessageBytes = new SeString(new Payload[] { - new UIForegroundPayload(this.Interface.Data, 502), - new TextPayload($"[{Name}] {message}"), - new UIForegroundPayload(this.Interface.Data, 0), - }).Encode(), + var message = string.Format(Language.LoadWarning, this.Name); + this.ChatGui.PrintChat(new XivChatEntry { + Name = this.Name, + Message = new SeString( + new UIForegroundPayload(502), + new TextPayload($"[{this.Name}] {message}"), + new UIForegroundPayload(0) + ), }); } diff --git a/SoundFilter/Ui/PluginUi.cs b/SoundFilter/Ui/PluginUi.cs index 8886b4b..ff46927 100755 --- a/SoundFilter/Ui/PluginUi.cs +++ b/SoundFilter/Ui/PluginUi.cs @@ -1,6 +1,6 @@ using System; using System.Globalization; -using Dalamud.Plugin; +using Dalamud.Logging; using SoundFilter.Resources; namespace SoundFilter.Ui { @@ -17,18 +17,19 @@ namespace SoundFilter.Ui { this.Settings = new Settings(this.Plugin); this.SoundLog = new SoundLog(this.Plugin); - this.Plugin.Interface.UiBuilder.OnBuildUi += this.Draw; - this.Plugin.Interface.OnLanguageChanged += this.ConfigureLanguage; + this.Plugin.Interface.UiBuilder.Draw += this.Draw; + this.Plugin.Interface.LanguageChanged += this.ConfigureLanguage; } public void Dispose() { - this.Plugin.Interface.OnLanguageChanged -= this.ConfigureLanguage; - this.Plugin.Interface.UiBuilder.OnBuildUi -= this.Draw; + this.Plugin.Interface.LanguageChanged -= this.ConfigureLanguage; + this.Plugin.Interface.UiBuilder.Draw -= this.Draw; this.Settings.Dispose(); } private void ConfigureLanguage(string? langCode = null) { + // ReSharper disable once ConstantNullCoalescingCondition langCode ??= this.Plugin.Interface.UiLanguage ?? "en"; try { Language.Culture = new CultureInfo(langCode); diff --git a/SoundFilter/Ui/Settings.cs b/SoundFilter/Ui/Settings.cs index 9049069..9c45212 100755 --- a/SoundFilter/Ui/Settings.cs +++ b/SoundFilter/Ui/Settings.cs @@ -17,14 +17,14 @@ namespace SoundFilter.Ui { this.Plugin = plugin; this.AddFilter = new AddFilter(plugin); - this.Plugin.Interface.UiBuilder.OnOpenConfigUi += this.Toggle; + this.Plugin.Interface.UiBuilder.OpenConfigUi += this.Toggle; } public void Dispose() { - this.Plugin.Interface.UiBuilder.OnOpenConfigUi -= this.Toggle; + this.Plugin.Interface.UiBuilder.OpenConfigUi -= this.Toggle; } - internal void Toggle(object? sender = null, object? args = null) { + internal void Toggle() { this._showWindow = !this._showWindow; } @@ -48,7 +48,7 @@ namespace SoundFilter.Ui { ImGui.SetNextWindowSize(new Vector2(500, 450), ImGuiCond.FirstUseEver); - var windowTitle = string.Format(Language.SettingsWindowTitle, SoundFilterPlugin.Name); + var windowTitle = string.Format(Language.SettingsWindowTitle, this.Plugin.Name); if (!ImGui.Begin($"{windowTitle}###soundfilter-settings", ref this._showWindow)) { ImGui.End(); return; diff --git a/SoundFilter/Util.cs b/SoundFilter/Util.cs index 0a62b95..ae4d797 100755 --- a/SoundFilter/Util.cs +++ b/SoundFilter/Util.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text; using Dalamud.Game; using Dalamud.Interface; diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..38c40573a730e063b0dbca599dd24a601a987f13 GIT binary patch literal 7240 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 literal 0 HcmV?d00001 diff --git a/icon.svg b/icon.svg new file mode 100755 index 0000000..f1400aa --- /dev/null +++ b/icon.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + Artboard 227 + + + + Artboard 227 + + + + + + + + + +