diff --git a/ScoutHelper/Configuration.cs b/ScoutHelper/Configuration.cs index 53b49e3..825b45e 100644 --- a/ScoutHelper/Configuration.cs +++ b/ScoutHelper/Configuration.cs @@ -19,6 +19,9 @@ public class Configuration : IPluginConfiguration { public string BearSiteTrainUrl { get; set; } = "https://tracker.beartoolkit.com/train"; public string BearTrainName { get; set; } = "Scout Helper Train"; + public string CopyTemplate { get; set; } = Constants.DefaultCopyTemplate; + public bool CopyFormattedText { get; set; } = false; + public void Initialize(DalamudPluginInterface pluginInterface) { this._pluginInterface = pluginInterface; } diff --git a/ScoutHelper/Constants.cs b/ScoutHelper/Constants.cs index 4f9b908..38f1a63 100644 --- a/ScoutHelper/Constants.cs +++ b/ScoutHelper/Constants.cs @@ -10,6 +10,8 @@ public static class Constants { public static readonly string PluginVersion; public static readonly string PluginNamespace = PluginName.Replace(" ", ""); #endregion + + public const string DefaultCopyTemplate = "{patch} {#}/{#available} {world} [{tracker}]({link})"; #region web constants public static readonly MediaTypeWithQualityHeaderValue MediaTypeJson = diff --git a/ScoutHelper/Managers/BearManager.cs b/ScoutHelper/Managers/BearManager.cs index 443d0f1..06f23ea 100644 --- a/ScoutHelper/Managers/BearManager.cs +++ b/ScoutHelper/Managers/BearManager.cs @@ -135,7 +135,7 @@ IList trainMobs } public static class BearExtensions { - private static readonly IDictionary BearPatchNames = new Dictionary { + private static readonly IReadOnlyDictionary BearPatchNames = new Dictionary { {Patch.ARR, "ARR"}, {Patch.HW, "HW"}, {Patch.SB, "SB"}, diff --git a/ScoutHelper/Models/TrainMob.cs b/ScoutHelper/Models/TrainMob.cs index 10bedd2..4b4f125 100644 --- a/ScoutHelper/Models/TrainMob.cs +++ b/ScoutHelper/Models/TrainMob.cs @@ -8,7 +8,7 @@ public record struct TrainMob( uint MobId, uint TerritoryId, uint MapId, - uint Instance, + uint? Instance, Vector2 Position, bool Dead, DateTime LastSeenUtc diff --git a/ScoutHelper/Plugin.cs b/ScoutHelper/Plugin.cs index 3c70bf1..8fb42a2 100644 --- a/ScoutHelper/Plugin.cs +++ b/ScoutHelper/Plugin.cs @@ -73,6 +73,8 @@ public void Dispose() { MainWindow.Dispose(); HuntHelperManager.Dispose(); + + Conf.Save(); } private static void OnLanguageChanged(string languageCode) { diff --git a/ScoutHelper/Utils.cs b/ScoutHelper/Utils.cs index 1570c0d..663c735 100644 --- a/ScoutHelper/Utils.cs +++ b/ScoutHelper/Utils.cs @@ -5,13 +5,14 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using ScoutHelper.Models; namespace ScoutHelper; public static class Utils { - public static string WorldName { - get => Plugin.ClientState.LocalPlayer?.CurrentWorld?.GameData?.Name.ToString() ?? "Not Found"; - } + public static string WorldName => Plugin.ClientState.LocalPlayer?.CurrentWorld?.GameData?.Name.ToString() ?? "Not Found"; public static string DataFilePath(string dataFilename) => Path.Combine( Plugin.PluginInterface.AssemblyLocation.Directory?.FullName!, @@ -27,6 +28,33 @@ public static void CreateTooltip(string text, float width = 12f) { ImGui.EndTooltip(); } + public static string FormatTemplate(string textTemplate, IList trainList, string bear, string url) { + + var regex = new Regex(@"\\?\{[^}]+\\?\}", RegexOptions.Compiled | RegexOptions.IgnoreCase); + var matches = regex.Matches(textTemplate); + + if (matches.Count == 0) { + return textTemplate; + } + + var s = new StringBuilder(textTemplate.Length); + var i = 0; + foreach (Match match in matches) { + var m = match.Value; + if (m[0] == '\\' || m[^2] == '\\') continue; + + s.Append(textTemplate.AsSpan(i, match.Index - i)); + + i = match.Index + match.Length; + } + + if (i < textTemplate.Length) { + s.Append(textTemplate.AsSpan(i)); + } + + return s.ToString(); + } + #region extensions public static void TaggedPrint(this IChatGui chatGui, string message) { chatGui.Print(message, Plugin.Name); @@ -36,7 +64,7 @@ public static void TaggedPrintError(this IChatGui chatGui, string message) { chatGui.PrintError(message, Plugin.Name); } - public static IDictionary VerifyEnumDictionary(this IDictionary enumDict) where K : struct, Enum { + public static IReadOnlyDictionary VerifyEnumDictionary(this IDictionary enumDict) where K : struct, Enum { var allEnumsAreInDict = (Enum.GetValuesAsUnderlyingType() as K[])!.All(enumDict.ContainsKey); if (!allEnumsAreInDict) { throw new Exception($"All values of enum [{typeof(K).Name}] must be in the dictionary."); diff --git a/ScoutHelper/Windows/MainWindow.cs b/ScoutHelper/Windows/MainWindow.cs index ee83fc6..a7e790f 100644 --- a/ScoutHelper/Windows/MainWindow.cs +++ b/ScoutHelper/Windows/MainWindow.cs @@ -1,10 +1,10 @@ using CSharpFunctionalExtensions; using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; -using Dalamud.Plugin.Services; using ImGuiNET; using ScoutHelper.Localization; using ScoutHelper.Managers; +using ScoutHelper.Models; using System; using System.Collections.Generic; using System.Linq; @@ -14,8 +14,12 @@ namespace ScoutHelper.Windows; public class MainWindow : Window, IDisposable { - private HuntHelperManager HuntHelperManager { get; init; } - private BearManager BearManager { get; init; } + private HuntHelperManager HuntHelperManager { get; } + private BearManager BearManager { get; } + + private readonly Vector2 _buttonSize; + private bool _copyFormattedText = Plugin.Conf.CopyFormattedText; + private string _textTemplate = Plugin.Conf.CopyTemplate; public MainWindow(HuntHelperManager huntHelperManager, BearManager bearManager) : base( Strings.MainWindowTitle, @@ -25,25 +29,75 @@ public MainWindow(HuntHelperManager huntHelperManager, BearManager bearManager) MinimumSize = new Vector2(64, 32), MaximumSize = new Vector2(float.MaxValue, float.MaxValue), }; + + _buttonSize = new List { + Strings.BearButton, + Strings.SirenButton + } + .Select(ImGuiHelpers.GetButtonSize) + .MaxBy(size => size.X); + _buttonSize.X += 4*ImGui.GetFontSize(); // add some horizontal padding + HuntHelperManager = huntHelperManager; BearManager = bearManager; } public void Dispose() { + Plugin.Conf.CopyFormattedText = _copyFormattedText; + Plugin.Conf.Save(); + GC.SuppressFinalize(this); } public override void Draw() { - var buttonSize = new List { - Strings.BearButton, - Strings.SirenButton - } - .Select(ImGuiHelpers.GetButtonSize) - .MaxBy(size => size.X); - buttonSize.X += ImGui.GetFontSize(); - - if (ImGui.Button(Strings.BearButton, buttonSize)) { + DrawModeButtons(); + + ImGui.Dummy(new Vector2(0, ImGui.GetStyle().FramePadding.Y)); + ImGui.Separator(); + ImGui.Dummy(new Vector2(0, ImGui.GetStyle().FramePadding.Y)); + + DrawGeneratorButtons(); + } + + private unsafe void DrawModeButtons() { + ImGuiHelpers.CenteredText("MODE"); + + var modeButtonSize = new Vector2( + _buttonSize.X / 2, + _buttonSize.Y - 4 + ); + var activeColor = new Vector4(0, 183, 165, 255)/255; + var inactiveColor = *ImGui.GetStyleColorVec4(ImGuiCol.Button); + var modeLink = !_copyFormattedText; + var modeFull = !modeLink; + var modeLinkColor = modeLink ? activeColor : inactiveColor; + var modeFullColor = modeFull ? activeColor : inactiveColor; + + ImGui.PushStyleColor(ImGuiCol.Button, modeLinkColor); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, modeLinkColor); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, modeLinkColor*0.9f); + if (ImGui.Button("link", modeButtonSize)) { + _copyFormattedText = !_copyFormattedText; + } + ImGui.PopStyleColor(3); + + ImGui.SameLine(); + + ImGui.SetCursorPosX(ImGui.GetWindowWidth() - ImGui.GetStyle().WindowPadding.X - modeButtonSize.X); + ImGui.PushStyleColor(ImGuiCol.Button, modeFullColor); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, modeFullColor); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, modeFullColor*0.9f); + if (ImGui.Button("full text", modeButtonSize)) { + _copyFormattedText = !_copyFormattedText; + } + ImGui.PopStyleColor(3); + } + + private void DrawGeneratorButtons() { + ImGuiHelpers.CenteredText("GENERATORS"); + + if (ImGui.Button(Strings.BearButton, _buttonSize)) { GenerateBearLink(); } if (ImGui.IsItemHovered()) { @@ -51,15 +105,16 @@ public override void Draw() { } ImGui.BeginDisabled(true); - if (ImGui.Button(Strings.SirenButton, buttonSize)) { } + if (ImGui.Button(Strings.SirenButton, _buttonSize)) { } ImGui.EndDisabled(); if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { Utils.CreateTooltip(Strings.SirenButtonTooltip); } } - + private void GenerateBearLink() { Plugin.ChatGui.TaggedPrint("Generating Bear link..."); + IList trainList = null!; HuntHelperManager .GetTrainList() @@ -68,16 +123,26 @@ private void GenerateBearLink() { "No mobs in the train :T" ) .Bind( - train => BearManager.GenerateBearLink(Utils.WorldName, train) - ) + train => { + trainList = train; + return BearManager.GenerateBearLink(Utils.WorldName, train); + }) .ContinueWith( apiResponseTask => { apiResponseTask .Result.Match( bearTrainLink => { - Plugin.ChatGui.TaggedPrint($"Copied link to clipboard: {bearTrainLink.Url}"); + Plugin.ChatGui.TaggedPrint($"Bear train link: {bearTrainLink.Url}"); Plugin.ChatGui.TaggedPrint($"Train admin password: {bearTrainLink.Pass}"); - ImGui.SetClipboardText(bearTrainLink.Url); + if (_copyFormattedText) { + var fullText = Utils.FormatTemplate(_textTemplate, trainList, "bear", bearTrainLink.Url); + ImGui.SetClipboardText(fullText); + Plugin.ChatGui.TaggedPrint($"Copied full text to clipboard: {fullText}"); + } + else { + ImGui.SetClipboardText(bearTrainLink.Url); + Plugin.ChatGui.TaggedPrint("Copied link to clipboard"); + } }, errorMessage => { Plugin.ChatGui.TaggedPrintError(errorMessage);