From b598c03e9e65f4771dcfdc168378e420a878fd25 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Tue, 26 May 2026 20:21:21 +0200 Subject: [PATCH] Apply csharpier reflow across source tree Reformats the entire Craftimizer source tree with dotnet csharpier 1.2.6 to match the Hellion Forge house style (matches what HellionChat enforces in its pre-push pipeline). Pure whitespace + using-block sorting; no semantic changes. This is a one-time noisy commit. Future code edits in this fork should land csharpier-clean because the pre-push hook (introduced in the next commit) runs `dotnet csharpier check Craftimizer/` as Block C of the preflight gate. Trade-off acknowledged: this widens the merge gap with upstream Craftimizer should Asriel ever resume maintenance. Given the upstream has been dormant since FFXIV 7.4 and the fork is light-rename only (internal namespaces unchanged), the marginal cost is acceptable. --- Craftimizer/Configuration.cs | 33 +- Craftimizer/ImGuiExtras.cs | 106 +- Craftimizer/ImGuiUtils.cs | 337 ++++-- Craftimizer/ImRaii2.cs | 11 +- Craftimizer/LuminaSheets.cs | 16 +- Craftimizer/Plugin.cs | 118 ++- Craftimizer/Service.cs | 63 +- Craftimizer/SimulatorUtils.cs | 140 ++- Craftimizer/Utils/AttributeCommandManager.cs | 29 +- Craftimizer/Utils/BackgroundTask.cs | 41 +- Craftimizer/Utils/CSRecipeNote.cs | 5 +- Craftimizer/Utils/Chat.cs | 34 +- Craftimizer/Utils/Colors.cs | 11 +- Craftimizer/Utils/CommunityMacros.cs | 160 ++- .../Utils/CraftimizerConflictDetector.cs | 8 +- Craftimizer/Utils/DynamicBars.cs | 102 +- Craftimizer/Utils/FoodStatus.cs | 62 +- Craftimizer/Utils/FuzzyMatcher.cs | 54 +- Craftimizer/Utils/Gearsets.cs | 81 +- Craftimizer/Utils/Hooks.cs | 74 +- Craftimizer/Utils/IconManager.cs | 18 +- Craftimizer/Utils/Ipc.cs | 26 +- Craftimizer/Utils/Log.cs | 3 +- Craftimizer/Utils/MacroCopy.cs | 153 +-- Craftimizer/Utils/MacroImport.cs | 81 +- Craftimizer/Utils/RecipeData.cs | 74 +- Craftimizer/Utils/SimulatedMacro.cs | 65 +- Craftimizer/Utils/SqText.cs | 14 +- Craftimizer/Utils/SynthesisValues.cs | 21 +- Craftimizer/Windows/MacroClipboard.cs | 66 +- Craftimizer/Windows/MacroEditor.cs | 975 +++++++++++++----- Craftimizer/Windows/MacroList.cs | 203 +++- Craftimizer/Windows/RecipeNote.cs | 693 +++++++++---- Craftimizer/Windows/Settings.cs | 505 +++++---- Craftimizer/Windows/SynthHelper.cs | 245 ++++- 35 files changed, 3329 insertions(+), 1298 deletions(-) diff --git a/Craftimizer/Configuration.cs b/Craftimizer/Configuration.cs index 88649f9..1eaf1c9 100644 --- a/Craftimizer/Configuration.cs +++ b/Craftimizer/Configuration.cs @@ -1,10 +1,10 @@ -using Craftimizer.Simulator.Actions; -using Craftimizer.Solver; using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Text.Json.Serialization; +using Craftimizer.Simulator.Actions; +using Craftimizer.Solver; namespace Craftimizer.Plugin; @@ -13,7 +13,8 @@ public class StoredActionTypeConverter : JsonConverter public override ActionType[] Read( ref Utf8JsonReader reader, Type typeToConvert, - JsonSerializerOptions options) + JsonSerializerOptions options + ) { if (reader.TokenType != JsonTokenType.StartArray) throw new JsonException(); @@ -87,7 +88,8 @@ public class StoredActionTypeConverter : JsonConverter public override void Write( Utf8JsonWriter writer, ActionType[] value, - JsonSerializerOptions options) + JsonSerializerOptions options + ) { writer.WriteStartArray(); foreach (var item in value) @@ -101,14 +103,18 @@ public class Macro public static event Action? OnMacroChanged; public string Name { get; set; } = string.Empty; - [JsonInclude] [JsonPropertyName("Actions")] + + [JsonInclude] + [JsonPropertyName("Actions")] internal ActionType[] actions { get; set; } = []; + [JsonIgnore] public IReadOnlyList Actions { get => actions; set => ActionEnumerable = value; } + [JsonIgnore] public IEnumerable ActionEnumerable { @@ -127,7 +133,7 @@ public class MacroCopyConfiguration OpenWindow, // useful for big macros CopyToMacro, // (add option for down or right) (max macro count; open copy-paste window if too much) CopyToClipboard, - CopyToMacroMate + CopyToMacroMate, } public CopyType Type { get; set; } = CopyType.OpenWindow; @@ -172,13 +178,15 @@ public partial class Configuration { Colorful, Simple, - None + None, } public static event Action? OnMacroListChanged; - [JsonInclude] [JsonPropertyName("Macros")] + [JsonInclude] + [JsonPropertyName("Macros")] internal List macros { get; private set; } = []; + [JsonIgnore] public IReadOnlyList Macros => macros; public int ReliabilitySimulationCount { get; set; } = 1000; @@ -244,10 +252,8 @@ public partial class Configuration [JsonSerializable(typeof(Configuration))] internal sealed partial class JsonContext : JsonSerializerContext { - public static JsonSerializerOptions DeserializeOptions { get; } = new() - { - Converters = { new StoredActionTypeConverter() } - }; + public static JsonSerializerOptions DeserializeOptions { get; } = + new() { Converters = { new StoredActionTypeConverter() } }; } public void Save() @@ -265,7 +271,8 @@ public partial class Configuration using var stream = f.OpenRead(); // System.InvalidOperationException: Setting init-only properties is not supported in source generation mode. - return JsonSerializer.Deserialize(stream, JsonContext.DeserializeOptions) ?? new(); + return JsonSerializer.Deserialize(stream, JsonContext.DeserializeOptions) + ?? new(); } return new(); } diff --git a/Craftimizer/ImGuiExtras.cs b/Craftimizer/ImGuiExtras.cs index 146e6fc..4f9527d 100644 --- a/Craftimizer/ImGuiExtras.cs +++ b/Craftimizer/ImGuiExtras.cs @@ -1,9 +1,9 @@ -using Dalamud.Bindings.ImGui; using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Dalamud.Bindings.ImGui; namespace Craftimizer.Plugin; @@ -11,22 +11,50 @@ internal static unsafe class ImGuiExtras { // https://github.com/ImGuiNET/ImGui.NET/blob/069363672fed940ebdaa02f9b032c282b66467c7/src/CodeGenerator/definitions/cimgui/definitions.json#L25394 [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] - private static extern unsafe byte igInputTextEx(byte* label, byte* hint, byte* buf, int buf_size, Vector2 size, ImGuiInputTextFlags flags, ImGuiInputTextCallback? callback, void* user_data); + private static extern unsafe byte igInputTextEx( + byte* label, + byte* hint, + byte* buf, + int buf_size, + Vector2 size, + ImGuiInputTextFlags flags, + ImGuiInputTextCallback? callback, + void* user_data + ); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] private static extern bool igItemAdd(Vector4 bb, uint id, Vector4* navBb, uint flags); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] - private static extern bool igButtonBehavior(Vector4 bb, uint id, bool* outHovered, bool* outHeld, ImGuiButtonFlags flags); + private static extern bool igButtonBehavior( + Vector4 bb, + uint id, + bool* outHovered, + bool* outHeld, + ImGuiButtonFlags flags + ); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] private static extern bool igItemSize_Vec2(Vector2 size, float text_baseline_y = -1.0f); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] - private static extern void igRenderFrame(Vector2 p_min, Vector2 p_max, uint fill_col, bool border = true, float rounding = 0.0f); + private static extern void igRenderFrame( + Vector2 p_min, + Vector2 p_max, + uint fill_col, + bool border = true, + float rounding = 0.0f + ); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] - private static extern void igRenderRectFilledRangeH(ImDrawList* draw_list, Vector4* rect, uint col, float x_start_norm, float x_end_norm, float rounding); + private static extern void igRenderRectFilledRangeH( + ImDrawList* draw_list, + Vector4* rect, + uint col, + float x_start_norm, + float x_end_norm, + float rounding + ); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] private static extern ImGuiItemFlags igGetItemFlags(); @@ -74,7 +102,16 @@ internal static unsafe class ImGuiExtras #endregion // Based off of code from InputTextWithHint: https://github.com/ImGuiNET/ImGui.NET/blob/069363672fed940ebdaa02f9b032c282b66467c7/src/ImGui.NET/ImGui.Manual.cs#L271 - public static unsafe bool InputTextEx(string label, string hint, ref string input, int maxLength, Vector2 size, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None, ImGuiInputTextCallback? callback = null, IntPtr user_data = default) + public static unsafe bool InputTextEx( + string label, + string hint, + ref string input, + int maxLength, + Vector2 size, + ImGuiInputTextFlags flags = ImGuiInputTextFlags.None, + ImGuiInputTextCallback? callback = null, + IntPtr user_data = default + ) { var utf8LabelByteCount = Encoding.UTF8.GetByteCount(label); byte* utf8LabelBytes; @@ -132,7 +169,8 @@ internal static unsafe class ImGuiExtras size, flags, callback, - user_data.ToPointer()); + user_data.ToPointer() + ); if (!AreStringsEqual(originalUtf8InputBytes, inputBufSize, utf8InputBytes)) { input = StringFromPtr(utf8InputBytes); @@ -155,8 +193,7 @@ internal static unsafe class ImGuiExtras return result != 0; } - public static unsafe bool ItemAdd(Vector4 bb, uint id) => - ItemAdd(bb, id, out _); + public static unsafe bool ItemAdd(Vector4 bb, uint id) => ItemAdd(bb, id, out _); public static unsafe bool ItemAdd(Vector4 bb, uint id, out Vector4 navBb, uint flags = 0) { @@ -166,7 +203,13 @@ internal static unsafe class ImGuiExtras } } - public static unsafe bool ButtonBehavior(Vector4 bb, uint id, out bool hovered, out bool held, ImGuiButtonFlags flags) + public static unsafe bool ButtonBehavior( + Vector4 bb, + uint id, + out bool hovered, + out bool held, + ImGuiButtonFlags flags + ) { fixed (bool* hoveredPtr = &hovered) fixed (bool* heldPtr = &held) @@ -175,19 +218,34 @@ internal static unsafe class ImGuiExtras } } - public static unsafe void RenderFrame(Vector2 p_min, Vector2 p_max, uint fill_col, bool border = true, float rounding = 0.0f) => - igRenderFrame(p_min, p_max, fill_col, border, rounding); + public static unsafe void RenderFrame( + Vector2 p_min, + Vector2 p_max, + uint fill_col, + bool border = true, + float rounding = 0.0f + ) => igRenderFrame(p_min, p_max, fill_col, border, rounding); - public static unsafe void RenderRectFilledRangeH(ImDrawListPtr draw_list, Vector4 rect, uint col, float x_start_norm, float x_end_norm, float rounding) => - igRenderRectFilledRangeH(draw_list, &rect, col, x_start_norm, x_end_norm, rounding); + public static unsafe void RenderRectFilledRangeH( + ImDrawListPtr draw_list, + Vector4 rect, + uint col, + float x_start_norm, + float x_end_norm, + float rounding + ) => igRenderRectFilledRangeH(draw_list, &rect, col, x_start_norm, x_end_norm, rounding); public static unsafe bool ItemSize(Vector2 size, float text_baseline_y = -1.0f) => igItemSize_Vec2(size, text_baseline_y); - public static unsafe ImGuiItemFlags GetItemFlags() => - igGetItemFlags(); + public static unsafe ImGuiItemFlags GetItemFlags() => igGetItemFlags(); - public static unsafe int? CalcWordWrapPositionA(this ImFontPtr font, float scale, ReadOnlySpan text, float wrap_width) + public static unsafe int? CalcWordWrapPositionA( + this ImFontPtr font, + float scale, + ReadOnlySpan text, + float wrap_width + ) { var utf8TextByteCount = Encoding.UTF8.GetByteCount(text); byte* utf8TextBytes; @@ -202,7 +260,13 @@ internal static unsafe class ImGuiExtras } GetUtf8(text, utf8TextBytes, utf8TextByteCount); - var ret = ImGuiNative.CalcWordWrapPositionA(font, scale, utf8TextBytes, utf8TextBytes + utf8TextByteCount, wrap_width); + var ret = ImGuiNative.CalcWordWrapPositionA( + font, + scale, + utf8TextBytes, + utf8TextBytes + utf8TextByteCount, + wrap_width + ); int? retVal = null; if (utf8TextBytes <= ret && ret <= utf8TextBytes + utf8TextByteCount) @@ -217,10 +281,12 @@ internal static unsafe class ImGuiExtras return retVal; } - public static unsafe bool SetDragDropPayload(string type, T data) where T : unmanaged => + public static unsafe bool SetDragDropPayload(string type, T data) + where T : unmanaged => ImGui.SetDragDropPayload(type, MemoryMarshal.AsBytes(new ReadOnlySpan(&data, 1))); - public static unsafe bool AcceptDragDropPayload(string type, out T data) where T : unmanaged + public static unsafe bool AcceptDragDropPayload(string type, out T data) + where T : unmanaged { var payload = ImGui.AcceptDragDropPayload(type); if (payload.IsNull || payload.DataSize != sizeof(T)) diff --git a/Craftimizer/ImGuiUtils.cs b/Craftimizer/ImGuiUtils.cs index 4fb876f..acbea8f 100644 --- a/Craftimizer/ImGuiUtils.cs +++ b/Craftimizer/ImGuiUtils.cs @@ -1,11 +1,3 @@ -using Craftimizer.Utils; -using Dalamud.Interface; -using Dalamud.Interface.ManagedFontAtlas; -using Dalamud.Interface.Utility; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; -using Dalamud.Bindings.ImPlot; -using MathNet.Numerics.Statistics; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -15,12 +7,24 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; +using Craftimizer.Utils; +using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImPlot; +using Dalamud.Interface; +using Dalamud.Interface.ManagedFontAtlas; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using MathNet.Numerics.Statistics; namespace Craftimizer.Plugin; internal static class ImGuiUtils { - private static readonly Stack<(Vector2 Min, Vector2 Max, float TopPadding)> GroupPanelLabelStack = new(); + private static readonly Stack<( + Vector2 Min, + Vector2 Max, + float TopPadding + )> GroupPanelLabelStack = new(); // Adapted from https://github.com/ocornut/imgui/issues/1496#issuecomment-655048353 // width = -1 -> size to parent @@ -62,7 +66,9 @@ internal static class ImGuiUtils var textFrameHeight = ImGui.GetFrameHeight(); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(name); - GroupPanelLabelStack.Push((ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), textFrameHeight / 2f)); // push rect to stack + GroupPanelLabelStack.Push( + (ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), textFrameHeight / 2f) + ); // push rect to stack ImGui.SameLine(0, 0); ImGui.Dummy(new Vector2(0f, textFrameHeight + itemSpacing.Y)); // shifts content by fh + is.y } @@ -112,18 +118,29 @@ internal static class ImGuiUtils { var (minClip, maxClip) = i switch { - 0 => (new Vector2(float.NegativeInfinity), new Vector2(labelMin.X, float.PositiveInfinity)), - 1 => (new Vector2(labelMax.X, float.NegativeInfinity), new Vector2(float.PositiveInfinity)), - 2 => (new Vector2(labelMin.X, float.NegativeInfinity), new Vector2(labelMax.X, labelMin.Y)), - 3 => (new Vector2(labelMin.X, labelMax.Y), new Vector2(labelMax.X, float.PositiveInfinity)), - _ => (Vector2.Zero, Vector2.Zero) + 0 => ( + new Vector2(float.NegativeInfinity), + new Vector2(labelMin.X, float.PositiveInfinity) + ), + 1 => ( + new Vector2(labelMax.X, float.NegativeInfinity), + new Vector2(float.PositiveInfinity) + ), + 2 => ( + new Vector2(labelMin.X, float.NegativeInfinity), + new Vector2(labelMax.X, labelMin.Y) + ), + 3 => ( + new Vector2(labelMin.X, labelMax.Y), + new Vector2(labelMax.X, float.PositiveInfinity) + ), + _ => (Vector2.Zero, Vector2.Zero), }; ImGui.PushClipRect(minClip, maxClip, true); - ImGui.GetWindowDrawList().AddRect( - innerMin, innerMax, - ImGui.GetColorU32(ImGuiCol.Border), - itemSpacing.X); + ImGui + .GetWindowDrawList() + .AddRect(innerMin, innerMax, ImGui.GetColorU32(ImGuiCol.Border), itemSpacing.X); ImGui.PopClipRect(); } @@ -143,15 +160,23 @@ internal static class ImGuiUtils } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float Lerp(float a, float b, float t) => - MathF.FusedMultiplyAdd(b - a, t, a); + private static float Lerp(float a, float b, float t) => MathF.FusedMultiplyAdd(b - a, t, a); private readonly record struct ArcEdge(float Angle, Vector2 Point) { - public ArcEdge(float angle) : this(angle, UnitCircle(angle)) { } + public ArcEdge(float angle) + : this(angle, UnitCircle(angle)) { } } - private static void ArcSegment(Vector2 o, ArcEdge prev, ArcEdge cur, ArcEdge? next, float radius, float ratio, uint color) + private static void ArcSegment( + Vector2 o, + ArcEdge prev, + ArcEdge cur, + ArcEdge? next, + float radius, + float ratio, + uint color + ) { var d = ImGui.GetWindowDrawList(); @@ -164,7 +189,15 @@ internal static class ImGuiUtils d.PathFillConvex(color); } - public static void Arc(float startAngle, float endAngle, float radius, float ratio, uint backgroundColor, uint filledColor, bool addDummy = true) + public static void Arc( + float startAngle, + float endAngle, + float radius, + float ratio, + uint backgroundColor, + uint filledColor, + bool addDummy = true + ) { // Fix normals when drawing (for antialiasing) if (startAngle > endAngle) @@ -224,9 +257,16 @@ internal static class ImGuiUtils ImGui.Dummy(new Vector2(radius * 2)); } - public static void ArcProgress(float value, float radius, float ratio, uint backgroundColor, uint filledColor) + public static void ArcProgress( + float value, + float radius, + float ratio, + uint backgroundColor, + uint filledColor + ) { - float startAngle, endAngle; + float startAngle, + endAngle; // https://github.com/ocornut/imgui/commit/c895e987adf746a997b655c64a6a8916c549ff6f#diff-d750e175eb584ba76bc560b8e54cf113ccbb31dd33f75078c1588925e197a3afR1304-R1310 if (value < 0) @@ -271,19 +311,34 @@ internal static class ImGuiUtils bar_end = bar_begin + bar_fraction; } - ImGuiExtras.RenderFrame(bbMin, bbMax, ImGui.GetColorU32(ImGuiCol.FrameBg), true, style.FrameRounding); + ImGuiExtras.RenderFrame( + bbMin, + bbMax, + ImGui.GetColorU32(ImGuiCol.FrameBg), + true, + style.FrameRounding + ); bbMin += new Vector2(style.FrameBorderSize); bbMax -= new Vector2(style.FrameBorderSize); - ImGuiExtras.RenderRectFilledRangeH(ImGui.GetWindowDrawList(), new(bbMin.X, bbMin.Y, bbMax.X, bbMax.Y), ImGui.GetColorU32(ImGuiCol.PlotHistogram), bar_begin, bar_end, style.FrameRounding); + ImGuiExtras.RenderRectFilledRangeH( + ImGui.GetWindowDrawList(), + new(bbMin.X, bbMin.Y, bbMax.X, bbMax.Y), + ImGui.GetColorU32(ImGuiCol.PlotHistogram), + bar_begin, + bar_end, + style.FrameRounding + ); } public sealed class ViolinData { public struct Point(float x, float y, float y2) { - public float X = x, Y = y, Y2 = y2; + public float X = x, + Y = y, + Y2 = y2; } public ReadOnlySpan Data => (DataArray ?? []).AsSpan(); @@ -291,7 +346,13 @@ internal static class ImGuiUtils public readonly float Min; public readonly float Max; - public ViolinData(IEnumerable samples, float min, float max, int resolution, double bandwidth) + public ViolinData( + IEnumerable samples, + float min, + float max, + int resolution, + double bandwidth + ) { Min = min; Max = max; @@ -300,9 +361,12 @@ internal static class ImGuiUtils _ = Task.Run(() => { var s = Stopwatch.StartNew(); - var data = ParallelEnumerable.Range(0, resolution + 1) + var data = ParallelEnumerable + .Range(0, resolution + 1) .Select(n => Lerp(min, max, n / (float)resolution)) - .Select(n => (n, (float)KernelDensity.EstimateGaussian(n, bandwidth, samplesList))) + .Select(n => + (n, (float)KernelDensity.EstimateGaussian(n, bandwidth, samplesList)) + ) .Select(n => new Point(n.n, n.Item2, -n.Item2)); // ParallelQuery doesn't support [.. data] correctly. The plots look very wrong. #pragma warning disable IDE0305 // Simplify collection initialization @@ -320,10 +384,22 @@ internal static class ImGuiUtils using var plotBg = ImRaii2.PushColor(ImPlotCol.Bg, Vector4.Zero); using var fill = ImRaii2.PushColor(ImPlotCol.Fill, Vector4.One.WithAlpha(.5f)); - using var plot = ImRaii2.Plot("##violin", size, ImPlotFlags.CanvasOnly | ImPlotFlags.NoInputs | ImPlotFlags.NoChild | ImPlotFlags.NoFrame); + using var plot = ImRaii2.Plot( + "##violin", + size, + ImPlotFlags.CanvasOnly + | ImPlotFlags.NoInputs + | ImPlotFlags.NoChild + | ImPlotFlags.NoFrame + ); if (plot.Success) { - ImPlot.SetupAxes([], [], ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations | ImPlotAxisFlags.AutoFit); + ImPlot.SetupAxes( + [], + [], + ImPlotAxisFlags.NoDecorations, + ImPlotAxisFlags.NoDecorations | ImPlotAxisFlags.AutoFit + ); ImPlot.SetupAxisLimits(ImAxis.X1, data.Min, data.Max, ImPlotCond.Always); ImPlot.SetupFinish(); @@ -334,14 +410,24 @@ internal static class ImGuiUtils var label_id = stackalloc byte[] { (byte)'\0' }; fixed (ViolinData.Point* p = points) { - ImPlot.PlotShaded(label_id, &p->X, &p->Y, &p->Y2, points.Length, ImPlotShadedFlags.None, 0, sizeof(ViolinData.Point)); + ImPlot.PlotShaded( + label_id, + &p->X, + &p->Y, + &p->Y2, + points.Length, + ImPlotShadedFlags.None, + 0, + sizeof(ViolinData.Point) + ); } } } } } - private sealed class SearchableComboData where T : IEquatable + private sealed class SearchableComboData + where T : IEquatable { public readonly ImmutableArray items; public List filteredItems; @@ -381,20 +467,26 @@ internal static class ImGuiUtils cts = new(); var token = cts.Token; task = Task.Run(() => FilterTask(inp, token), token) - .ContinueWith(t => - { - if (cts.IsCancellationRequested) - return; + .ContinueWith( + t => + { + if (cts.IsCancellationRequested) + return; - try - { - t.Exception!.Flatten().Handle(ex => ex is TaskCanceledException or OperationCanceledException); - } - catch (Exception e) - { - Log.Error(e, "Filtering recipes failed"); - } - }, TaskContinuationOptions.OnlyOnFaulted); + try + { + t.Exception!.Flatten() + .Handle(ex => + ex is TaskCanceledException or OperationCanceledException + ); + } + catch (Exception e) + { + Log.Error(e, "Filtering recipes failed"); + } + }, + TaskContinuationOptions.OnlyOnFaulted + ); } private void FilterTask(string input, CancellationToken token) @@ -405,7 +497,9 @@ internal static class ImGuiUtils return; } var matcher = new FuzzyMatcher(input.ToLowerInvariant(), MatchMode.FuzzyParts); - var query = items.AsParallel().Select(i => (Item: i, Score: matcher.Matches(getString(i).ToLowerInvariant()))) + var query = items + .AsParallel() + .Select(i => (Item: i, Score: matcher.Matches(getString(i).ToLowerInvariant()))) .Where(t => t.Score > 0) .OrderByDescending(t => t.Score) .Select(t => t.Item); @@ -413,16 +507,34 @@ internal static class ImGuiUtils filteredItems = [.. query]; } } + private static readonly Dictionary ComboData = []; - private static SearchableComboData GetComboData(uint comboKey, IEnumerable items, T selectedItem, Func getString) where T : IEquatable => + private static SearchableComboData GetComboData( + uint comboKey, + IEnumerable items, + T selectedItem, + Func getString + ) + where T : IEquatable => (SearchableComboData)( ComboData.TryGetValue(comboKey, out var data) - ? data - : ComboData[comboKey] = new SearchableComboData(items, selectedItem, getString)); + ? data + : ComboData[comboKey] = new SearchableComboData(items, selectedItem, getString) + ); // https://github.com/ocornut/imgui/issues/718#issuecomment-1563162222 - public static bool SearchableCombo(string id, ref T selectedItem, IEnumerable items, ImFontPtr selectableFont, float width, Func getString, Func getId, Action draw) where T : IEquatable + public static bool SearchableCombo( + string id, + ref T selectedItem, + IEnumerable items, + ImFontPtr selectableFont, + float width, + Func getString, + Func getId, + Action draw + ) + where T : IEquatable { var comboKey = ImGui.GetID(id); var data = GetComboData(comboKey, items, selectedItem, getString); @@ -433,7 +545,12 @@ internal static class ImGuiUtils width = width == 0 ? ImGui.GetContentRegionAvail().X : width; var availableSpace = Math.Min(ImGui.GetContentRegionAvail().X, width); ImGui.SetNextItemWidth(availableSpace); - var isInputTextEnterPressed = ImGui.InputText("##input", ref data.input, 256, ImGuiInputTextFlags.EnterReturnsTrue); + var isInputTextEnterPressed = ImGui.InputText( + "##input", + ref data.input, + 256, + ImGuiInputTextFlags.EnterReturnsTrue + ); var min = ImGui.GetItemRectMin(); var size = ImGui.GetItemRectSize(); size.X = Math.Min(size.X, availableSpace); @@ -447,7 +564,15 @@ internal static class ImGuiUtils data.wasTextActive = false; } - using (var popup = ImRaii.Popup("##popup", ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings)) + using ( + var popup = ImRaii.Popup( + "##popup", + ImGuiWindowFlags.NoMove + | ImGuiWindowFlags.NoResize + | ImGuiWindowFlags.AlwaysAutoResize + | ImGuiWindowFlags.NoSavedSettings + ) + ) { if (popup) { @@ -466,25 +591,36 @@ internal static class ImGuiUtils isInputTextEnterPressed = true; data.wasTextActive = isActive; - using (var scrollingRegion = ImRaii.Child("scrollingRegion", new Vector2(size.X, size.Y * 10), false, ImGuiWindowFlags.HorizontalScrollbar)) + using ( + var scrollingRegion = ImRaii.Child( + "scrollingRegion", + new Vector2(size.X, size.Y * 10), + false, + ImGuiWindowFlags.HorizontalScrollbar + ) + ) { T? _selectedItem = default; var height = ImGui.GetTextLineHeight(); - var r = ListClip(data.filteredItems, height, t => - { - var name = getString(t); - using (var selectFont = ImRaii.PushFont(selectableFont)) + var r = ListClip( + data.filteredItems, + height, + t => { - if (ImGui.Selectable($"##{getId(t)}")) + var name = getString(t); + using (var selectFont = ImRaii.PushFont(selectableFont)) { - _selectedItem = t; - return true; + if (ImGui.Selectable($"##{getId(t)}")) + { + _selectedItem = t; + return true; + } } + ImGui.SameLine(0, ImGui.GetStyle().ItemSpacing.X / 2f); + draw(t); + return false; } - ImGui.SameLine(0, ImGui.GetStyle().ItemSpacing.X / 2f); - draw(t); - return false; - }); + ); if (r) { selectedItem = _selectedItem!; @@ -530,7 +666,11 @@ internal static class ImGuiUtils imGuiListClipperPtr.Begin(data.Count, lineHeight); while (imGuiListClipperPtr.Step()) { - for (var i = imGuiListClipperPtr.DisplayStart; i <= imGuiListClipperPtr.DisplayEnd; i++) + for ( + var i = imGuiListClipperPtr.DisplayStart; + i <= imGuiListClipperPtr.DisplayEnd; + i++ + ) { if (i >= data.Count) return false; @@ -551,10 +691,28 @@ internal static class ImGuiUtils } } - public static bool InputTextMultilineWithHint(string label, string hint, ref string input, int maxLength, Vector2 size, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None, ImGuiInputTextCallback? callback = null, IntPtr user_data = default) + public static bool InputTextMultilineWithHint( + string label, + string hint, + ref string input, + int maxLength, + Vector2 size, + ImGuiInputTextFlags flags = ImGuiInputTextFlags.None, + ImGuiInputTextCallback? callback = null, + IntPtr user_data = default + ) { const ImGuiInputTextFlags Multiline = (ImGuiInputTextFlags)(1 << 26); - return ImGuiExtras.InputTextEx(label, hint, ref input, maxLength, size, flags | Multiline, callback, user_data); + return ImGuiExtras.InputTextEx( + label, + hint, + ref input, + maxLength, + size, + flags | Multiline, + callback, + user_data + ); } private static Vector2 GetIconSize(FontAwesomeIcon icon) @@ -563,7 +721,12 @@ internal static class ImGuiUtils return ImGui.CalcTextSize(icon.ToIconString()); } - private static void DrawCenteredIcon(FontAwesomeIcon icon, Vector2 offset, Vector2 size, bool isDisabled = false) + private static void DrawCenteredIcon( + FontAwesomeIcon icon, + Vector2 offset, + Vector2 size, + bool isDisabled = false + ) { var iconSize = GetIconSize(icon); @@ -585,7 +748,15 @@ internal static class ImGuiUtils iconOffset = Vector2.Zero; } - ImGui.GetWindowDrawList().AddText(UiBuilder.IconFont, UiBuilder.IconFont.FontSize * ImGuiHelpers.GlobalScale * scale, offset + iconOffset, ImGui.GetColorU32(!isDisabled ? ImGuiCol.Text : ImGuiCol.TextDisabled), icon.ToIconString()); + ImGui + .GetWindowDrawList() + .AddText( + UiBuilder.IconFont, + UiBuilder.IconFont.FontSize * ImGuiHelpers.GlobalScale * scale, + offset + iconOffset, + ImGui.GetColorU32(!isDisabled ? ImGuiCol.Text : ImGuiCol.TextDisabled), + icon.ToIconString() + ); } public static bool IconButtonSquare(FontAwesomeIcon icon, float size = -1) @@ -627,7 +798,13 @@ internal static class ImGuiUtils Dalamud.Utility.Util.OpenLink(url); var urlWithoutScheme = url; if (Uri.TryCreate(url, UriKind.Absolute, out var uri)) - urlWithoutScheme = uri.Host + (string.Equals(uri.PathAndQuery, "/", StringComparison.Ordinal) ? string.Empty : uri.PathAndQuery); + urlWithoutScheme = + uri.Host + + ( + string.Equals(uri.PathAndQuery, "/", StringComparison.Ordinal) + ? string.Empty + : uri.PathAndQuery + ); Tooltip(urlWithoutScheme); } } @@ -647,7 +824,11 @@ internal static class ImGuiUtils ImGui.TextUnformatted(text); } - public static void TextWrappedTo(string text, float wrapPosX = default, float basePosX = default) + public static void TextWrappedTo( + string text, + float wrapPosX = default, + float basePosX = default + ) { var font = ImGui.GetFont(); @@ -663,7 +844,11 @@ internal static class ImGuiUtils currentWrapWidth = wrapPosX - currentPos; var textBuf = text.AsSpan(); - var lineSize = font.CalcWordWrapPositionA(ImGuiHelpers.GlobalScale, textBuf, currentWrapWidth); + var lineSize = font.CalcWordWrapPositionA( + ImGuiHelpers.GlobalScale, + textBuf, + currentWrapWidth + ); if (lineSize == 0) lineSize = textBuf.Length; var lineBuf = textBuf[..lineSize]; diff --git a/Craftimizer/ImRaii2.cs b/Craftimizer/ImRaii2.cs index b25164d..1726be1 100644 --- a/Craftimizer/ImRaii2.cs +++ b/Craftimizer/ImRaii2.cs @@ -1,8 +1,8 @@ -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; -using Dalamud.Bindings.ImPlot; using System; using System.Numerics; +using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImPlot; +using Dalamud.Interface.Utility.Raii; namespace Craftimizer.Plugin; @@ -61,7 +61,10 @@ public static class ImRaii2 public static IEndObject Plot(string title_id, Vector2 size, ImPlotFlags flags) { - return new EndConditionally(new Action(ImPlot.EndPlot), ImPlot.BeginPlot(title_id, size, flags)); + return new EndConditionally( + new Action(ImPlot.EndPlot), + ImPlot.BeginPlot(title_id, size, flags) + ); } public static IEndObject PushStyle(ImPlotStyleVar idx, Vector2 val) diff --git a/Craftimizer/LuminaSheets.cs b/Craftimizer/LuminaSheets.cs index 53a58e2..9b27d5a 100644 --- a/Craftimizer/LuminaSheets.cs +++ b/Craftimizer/LuminaSheets.cs @@ -10,18 +10,24 @@ public static class LuminaSheets public static readonly ExcelSheet RecipeSheet = Module.GetSheet(); public static readonly ExcelSheet ActionSheet = Module.GetSheet(); - public static readonly ExcelSheet CraftActionSheet = Module.GetSheet(); + public static readonly ExcelSheet CraftActionSheet = + Module.GetSheet(); public static readonly ExcelSheet StatusSheet = Module.GetSheet(); public static readonly ExcelSheet AddonSheet = Module.GetSheet(); public static readonly ExcelSheet ClassJobSheet = Module.GetSheet(); public static readonly ExcelSheet ItemSheet = Module.GetSheet(); - public static readonly ExcelSheet ItemSheetEnglish = Module.GetSheet(Language.English)!; + public static readonly ExcelSheet ItemSheetEnglish = Module.GetSheet( + Language.English + )!; public static readonly ExcelSheet LevelSheet = Module.GetSheet(); public static readonly ExcelSheet QuestSheet = Module.GetSheet(); public static readonly ExcelSheet MateriaSheet = Module.GetSheet(); public static readonly ExcelSheet BaseParamSheet = Module.GetSheet(); public static readonly ExcelSheet ItemFoodSheet = Module.GetSheet(); - public static readonly ExcelSheet WKSMissionToDoEvalutionRefinSheet = Module.GetSheet(); - public static readonly ExcelSheet RecipeLevelTableSheet = Module.GetSheet(); - public static readonly ExcelSheet GathererCrafterLvAdjustTableSheet = Module.GetSheet(); + public static readonly ExcelSheet WKSMissionToDoEvalutionRefinSheet = + Module.GetSheet(); + public static readonly ExcelSheet RecipeLevelTableSheet = + Module.GetSheet(); + public static readonly ExcelSheet GathererCrafterLvAdjustTableSheet = + Module.GetSheet(); } diff --git a/Craftimizer/Plugin.cs b/Craftimizer/Plugin.cs index d8a0220..4609b57 100644 --- a/Craftimizer/Plugin.cs +++ b/Craftimizer/Plugin.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; +using System.Reflection; using Craftimizer.Plugin.Windows; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; @@ -6,9 +9,6 @@ using Craftimizer.Windows; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.Windowing; using Dalamud.Plugin; -using System; -using System.Collections.Generic; -using System.Reflection; namespace Craftimizer.Plugin; @@ -50,9 +50,13 @@ public sealed class Plugin : IDalamudPlugin AttributeCommandManager = new(); var assembly = Assembly.GetExecutingAssembly(); - Version = assembly.GetCustomAttribute()!.InformationalVersion.Split('+')[0]; + Version = assembly + .GetCustomAttribute()! + .InformationalVersion.Split('+')[0]; Author = assembly.GetCustomAttribute()!.Company; - BuildConfiguration = assembly.GetCustomAttribute()!.Configuration; + BuildConfiguration = assembly + .GetCustomAttribute()! + .Configuration; if (DateTime.Now is { Day: 1, Month: 4 }) Icon = IconManager.GetAssemblyTexture("Graphics.horse_icon.png"); else @@ -72,59 +76,93 @@ public sealed class Plugin : IDalamudPlugin Service.PluginInterface.UiBuilder.OpenMainUi += OpenCraftingLog; } - public (CharacterStats? Character, RecipeData? Recipe, MacroEditor.CrafterBuffs? Buffs) GetOpenedStats() + public ( + CharacterStats? Character, + RecipeData? Recipe, + MacroEditor.CrafterBuffs? Buffs + ) GetOpenedStats() { var editorWindow = (EditorWindow?.IsOpen ?? false) ? EditorWindow : null; var recipeData = editorWindow?.RecipeData ?? Service.Plugin.RecipeNoteWindow.RecipeData; - var characterStats = editorWindow?.CharacterStats ?? Service.Plugin.RecipeNoteWindow.CharacterStats; - var buffs = editorWindow?.Buffs ?? (RecipeNoteWindow.CharacterStats != null ? new(Service.Objects.LocalPlayer?.StatusList) : null); + var characterStats = + editorWindow?.CharacterStats ?? Service.Plugin.RecipeNoteWindow.CharacterStats; + var buffs = + editorWindow?.Buffs + ?? ( + RecipeNoteWindow.CharacterStats != null + ? new(Service.Objects.LocalPlayer?.StatusList) + : null + ); return (characterStats, recipeData, buffs); } - public (CharacterStats Character, RecipeData Recipe, MacroEditor.CrafterBuffs Buffs) GetDefaultStats() + public ( + CharacterStats Character, + RecipeData Recipe, + MacroEditor.CrafterBuffs Buffs + ) GetDefaultStats() { var stats = GetOpenedStats(); return ( - stats.Character ?? new() - { - Craftsmanship = 100, - Control = 100, - CP = 200, - Level = 10, - CanUseManipulation = false, - HasSplendorousBuff = false, - IsSpecialist = false, - }, + stats.Character + ?? new() + { + Craftsmanship = 100, + Control = 100, + CP = 200, + Level = 10, + CanUseManipulation = false, + HasSplendorousBuff = false, + IsSpecialist = false, + }, stats.Recipe ?? new(1023), stats.Buffs ?? new(null) ); } - [Command(name: "/crafteditor", aliases: "/macroeditor", description: "Open the crafting macro editor.")] + [Command( + name: "/crafteditor", + aliases: "/macroeditor", + description: "Open the crafting macro editor." + )] public void OpenEmptyMacroEditor() { var stats = GetDefaultStats(); OpenMacroEditor(stats.Character, stats.Recipe, stats.Buffs, null, [], null); } - public void OpenMacroEditor(CharacterStats characterStats, RecipeData recipeData, MacroEditor.CrafterBuffs buffs, IEnumerable? ingredientHqCounts, IEnumerable actions, Action>? setter) + public void OpenMacroEditor( + CharacterStats characterStats, + RecipeData recipeData, + MacroEditor.CrafterBuffs buffs, + IEnumerable? ingredientHqCounts, + IEnumerable actions, + Action>? setter + ) { EditorWindow?.Dispose(); EditorWindow = new(characterStats, recipeData, buffs, ingredientHqCounts, actions, setter); } - [Command(name: "/craftaction", description: "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.")] - public void ExecuteSuggestedSynthHelperAction() => - SynthHelperWindow.ExecuteNextAction(); + [Command( + name: "/craftaction", + description: "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players." + )] + public void ExecuteSuggestedSynthHelperAction() => SynthHelperWindow.ExecuteNextAction(); - [Command(name: "/craftretry", description: "Clicks \"Retry\" in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.")] - public void ExecuteRetrySynthHelper() => - SynthHelperWindow.AttemptRetry(); + [Command( + name: "/craftretry", + description: "Clicks \"Retry\" in the synthesis helper. Can also be run inside a macro. This command is useful for controller players." + )] + public void ExecuteRetrySynthHelper() => SynthHelperWindow.AttemptRetry(); - [Command(name: "/craftimizer", aliases: "/forgeimizer", description: "Open the settings window.")] - private void OpenSettingsWindowForced() => - OpenSettingsWindow(true); + [Command( + name: "/craftimizer", + aliases: "/forgeimizer", + description: "Open the settings window." + )] + private void OpenSettingsWindowForced() => OpenSettingsWindow(true); public void OpenSettingsWindow(bool force = false) { @@ -138,7 +176,11 @@ public sealed class Plugin : IDalamudPlugin SettingsWindow.SelectTab(selectedTabLabel); } - [Command(name: "/craftmacros", aliases: "/macrolist", description: "Open the crafting macros window.")] + [Command( + name: "/craftmacros", + aliases: "/macrolist", + description: "Open the crafting macros window." + )] public void OpenMacroListWindow() { ListWindow.IsOpen = true; @@ -157,12 +199,14 @@ public sealed class Plugin : IDalamudPlugin } public static IActiveNotification DisplaySolverWarning(string text) => - DisplayNotification(new() - { - Content = text, - Title = "Solver Warning", - Type = NotificationType.Warning - }); + DisplayNotification( + new() + { + Content = text, + Title = "Solver Warning", + Type = NotificationType.Warning, + } + ); public static IActiveNotification DisplayNotification(Notification notification) { diff --git a/Craftimizer/Service.cs b/Craftimizer/Service.cs index f38dad0..7a24d75 100644 --- a/Craftimizer/Service.cs +++ b/Craftimizer/Service.cs @@ -14,22 +14,53 @@ namespace Craftimizer.Plugin; public sealed class Service { #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - [PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } - [PluginService] public static ICommandManager CommandManager { get; private set; } - [PluginService] public static IObjectTable Objects { get; private set; } - [PluginService] public static ISigScanner SigScanner { get; private set; } - [PluginService] public static IGameGui GameGui { get; private set; } - [PluginService] public static IClientState ClientState { get; private set; } - [PluginService] public static IDataManager DataManager { get; private set; } - [PluginService] public static ITextureProvider TextureProvider { get; private set; } - [PluginService] public static IDalamudAssetManager DalamudAssetManager { get; private set; } - [PluginService] public static ITargetManager TargetManager { get; private set; } - [PluginService] public static ICondition Condition { get; private set; } - [PluginService] public static IFramework Framework { get; private set; } - [PluginService] public static IPluginLog PluginLog { get; private set; } - [PluginService] public static IGameInteropProvider GameInteropProvider { get; private set; } - [PluginService] public static INotificationManager NotificationManager { get; private set; } - [PluginService] public static ISeStringEvaluator SeStringEvaluator { get; private set; } + [PluginService] + public static IDalamudPluginInterface PluginInterface { get; private set; } + + [PluginService] + public static ICommandManager CommandManager { get; private set; } + + [PluginService] + public static IObjectTable Objects { get; private set; } + + [PluginService] + public static ISigScanner SigScanner { get; private set; } + + [PluginService] + public static IGameGui GameGui { get; private set; } + + [PluginService] + public static IClientState ClientState { get; private set; } + + [PluginService] + public static IDataManager DataManager { get; private set; } + + [PluginService] + public static ITextureProvider TextureProvider { get; private set; } + + [PluginService] + public static IDalamudAssetManager DalamudAssetManager { get; private set; } + + [PluginService] + public static ITargetManager TargetManager { get; private set; } + + [PluginService] + public static ICondition Condition { get; private set; } + + [PluginService] + public static IFramework Framework { get; private set; } + + [PluginService] + public static IPluginLog PluginLog { get; private set; } + + [PluginService] + public static IGameInteropProvider GameInteropProvider { get; private set; } + + [PluginService] + public static INotificationManager NotificationManager { get; private set; } + + [PluginService] + public static ISeStringEvaluator SeStringEvaluator { get; private set; } public static Plugin Plugin { get; private set; } public static Configuration Configuration => Plugin.Configuration; diff --git a/Craftimizer/SimulatorUtils.cs b/Craftimizer/SimulatorUtils.cs index 4e02f6f..59860ee 100644 --- a/Craftimizer/SimulatorUtils.cs +++ b/Craftimizer/SimulatorUtils.cs @@ -1,21 +1,21 @@ -using Craftimizer.Simulator; -using Craftimizer.Simulator.Actions; -using FFXIVClientStructs.FFXIV.Client.Game.UI; using System; using System.Linq; using System.Numerics; using System.Text; +using Craftimizer.Simulator; +using Craftimizer.Simulator.Actions; +using Craftimizer.Utils; +using Dalamud.Utility; +using FFXIVClientStructs.FFXIV.Client.Game.Event; +using FFXIVClientStructs.FFXIV.Client.Game.UI; +using Lumina.Excel.Sheets; +using Lumina.Text.Payloads; +using Lumina.Text.ReadOnly; using Action = Lumina.Excel.Sheets.Action; using ActionType = Craftimizer.Simulator.Actions.ActionType; using ClassJob = Craftimizer.Simulator.ClassJob; using Condition = Craftimizer.Simulator.Condition; using Status = Lumina.Excel.Sheets.Status; -using Craftimizer.Utils; -using Lumina.Text.ReadOnly; -using Lumina.Text.Payloads; -using Lumina.Excel.Sheets; -using Dalamud.Utility; -using FFXIVClientStructs.FFXIV.Client.Game.Event; namespace Craftimizer.Plugin; @@ -27,7 +27,10 @@ internal static class ActionUtils { var actionTypes = Enum.GetValues(); var classJobs = Enum.GetValues(); - ActionRows = new (CraftAction? CraftAction, Action? Action)[actionTypes.Length, classJobs.Length]; + ActionRows = new (CraftAction? CraftAction, Action? Action)[ + actionTypes.Length, + classJobs.Length + ]; foreach (var actionType in actionTypes) { var actionId = actionType.Base().ActionId; @@ -35,37 +38,48 @@ internal static class ActionUtils { foreach (var classJob in classJobs) { - ActionRows[(int)actionType, (int)classJob] = (classJob switch - { - ClassJob.Carpenter => baseCraftAction.CRP.Value, - ClassJob.Blacksmith => baseCraftAction.BSM.Value, - ClassJob.Armorer => baseCraftAction.ARM.Value, - ClassJob.Goldsmith => baseCraftAction.GSM.Value, - ClassJob.Leatherworker => baseCraftAction.LTW.Value, - ClassJob.Weaver => baseCraftAction.WVR.Value, - ClassJob.Alchemist => baseCraftAction.ALC.Value, - ClassJob.Culinarian => baseCraftAction.CUL.Value, - _ => baseCraftAction - }, null); + ActionRows[(int)actionType, (int)classJob] = ( + classJob switch + { + ClassJob.Carpenter => baseCraftAction.CRP.Value, + ClassJob.Blacksmith => baseCraftAction.BSM.Value, + ClassJob.Armorer => baseCraftAction.ARM.Value, + ClassJob.Goldsmith => baseCraftAction.GSM.Value, + ClassJob.Leatherworker => baseCraftAction.LTW.Value, + ClassJob.Weaver => baseCraftAction.WVR.Value, + ClassJob.Alchemist => baseCraftAction.ALC.Value, + ClassJob.Culinarian => baseCraftAction.CUL.Value, + _ => baseCraftAction, + }, + null + ); } } if (LuminaSheets.ActionSheet.GetRowOrDefault(actionId) is { } baseAction) { var possibleActions = LuminaSheets.ActionSheet.Where(r => - r.Icon == baseAction.Icon && - r.ActionCategory.RowId == baseAction.ActionCategory.RowId && - r.Name.Equals(baseAction.Name)); + r.Icon == baseAction.Icon + && r.ActionCategory.RowId == baseAction.ActionCategory.RowId + && r.Name.Equals(baseAction.Name) + ); foreach (var classJob in classJobs) - ActionRows[(int)actionType, (int)classJob] = (null, possibleActions.First(r => r.ClassJobCategory.ValueNullable?.IsClassJob(classJob) ?? false)); + ActionRows[(int)actionType, (int)classJob] = ( + null, + possibleActions.First(r => + r.ClassJobCategory.ValueNullable?.IsClassJob(classJob) ?? false + ) + ); } } } public static void Initialize() { } - public static (CraftAction? CraftAction, Action? Action) GetActionRow(this ActionType me, ClassJob classJob) => - ActionRows[(int)me, (int)classJob]; + public static (CraftAction? CraftAction, Action? Action) GetActionRow( + this ActionType me, + ClassJob classJob + ) => ActionRows[(int)me, (int)classJob]; public static uint GetId(this ActionType me, ClassJob classJob) { @@ -86,7 +100,11 @@ internal static class ActionUtils return Service.IconManager.GetIconCached(craftAction?.Icon ?? action?.Icon ?? 1953); } - public static ActionType? GetActionTypeFromId(uint actionId, ClassJob classJob, bool isCraftAction) + public static ActionType? GetActionTypeFromId( + uint actionId, + ClassJob classJob, + bool isCraftAction + ) { foreach (var action in Enum.GetValues()) { @@ -119,7 +137,7 @@ internal static class ClassJobUtils ClassJob.Weaver => 13, ClassJob.Alchemist => 14, ClassJob.Culinarian => 15, - _ => 0 + _ => 0, }; public static ClassJob? GetClassJobFromIdx(byte classJobIdx) => @@ -133,7 +151,7 @@ internal static class ClassJobUtils 13 => ClassJob.Weaver, 14 => ClassJob.Alchemist, 15 => ClassJob.Culinarian, - _ => null + _ => null, }; public static sbyte GetExpArrayIdx(this ClassJob me) => @@ -158,7 +176,11 @@ internal static class ClassJobUtils } public static unsafe bool CanPlayerUseManipulation(this ClassJob me) => - UIState.Instance()->IsUnlockLinkUnlockedOrQuestCompleted(ActionType.Manipulation.GetActionRow(me).Action!.Value.UnlockLink.RowId); + UIState + .Instance() + ->IsUnlockLinkUnlockedOrQuestCompleted( + ActionType.Manipulation.GetActionRow(me).Action!.Value.UnlockLink.RowId + ); public static string GetName(this ClassJob me) { @@ -186,8 +208,7 @@ internal static class ClassJobUtils public static Quest GetUnlockQuest(this ClassJob me) => LuminaSheets.QuestSheet.GetRow(65720 + (uint)me); - public static ushort GetIconId(this ClassJob me) => - (ushort)(62000 + me.GetClassJobIndex()); + public static ushort GetIconId(this ClassJob me) => (ushort)(62000 + me.GetClassJobIndex()); public static bool IsClassJob(this ClassJobCategory me, ClassJob classJob) => classJob switch @@ -200,7 +221,7 @@ internal static class ClassJobUtils ClassJob.Weaver => me.WVR, ClassJob.Alchemist => me.ALC, ClassJob.Culinarian => me.CUL, - _ => false + _ => false, }; } @@ -219,7 +240,7 @@ internal static class ConditionUtils Condition.Malleable => (13455, 14208), Condition.Primed => (13454, 14207), Condition.GoodOmen => (14214, 14215), - _ => (226, 14200) // Unknown + _ => (226, 14200), // Unknown }; private static Vector3 AddRGB(this Condition me) => @@ -235,10 +256,11 @@ internal static class ConditionUtils Condition.Malleable => new(-80, -40, 180), Condition.Primed => new(30, -155, 200), Condition.GoodOmen => new(100, 20, 0), - _ => Vector3.Zero // Unknown + _ => Vector3.Zero, // Unknown }; private const float ConditionCyclePeriod = 19 / 30f; + // The real period of all condition color cycles are 0.633... (19/30) seconds // Interp accepts 0-1 public static Vector4 GetColor(this Condition me, float interp) @@ -252,12 +274,32 @@ internal static class ConditionUtils addRgb = interp switch { < 0.155f => Vector3.Lerp(new(128, 0, 0), new(128, 80, 0), (interp - 0) / 0.155f), - < 0.315f => Vector3.Lerp(new(128, 80, 0), new(128, 128, 0), (interp - 0.155f) / 0.16f), - < 0.475f => Vector3.Lerp(new(128, 128, 0), new(0, 64, 0), (interp - 0.315f) / 0.16f), - < 0.630f => Vector3.Lerp(new(0, 64, 0), new(0, 128, 128), (interp - 0.475f) / 0.155f), - < 0.790f => Vector3.Lerp(new(0, 128, 128), new(0, 0, 128), (interp - 0.630f) / 0.16f), - < 0.945f => Vector3.Lerp(new(0, 0, 128), new(64, 0, 64), (interp - 0.790f) / 0.155f), - _ => new(64, 0, 64) + < 0.315f => Vector3.Lerp( + new(128, 80, 0), + new(128, 128, 0), + (interp - 0.155f) / 0.16f + ), + < 0.475f => Vector3.Lerp( + new(128, 128, 0), + new(0, 64, 0), + (interp - 0.315f) / 0.16f + ), + < 0.630f => Vector3.Lerp( + new(0, 64, 0), + new(0, 128, 128), + (interp - 0.475f) / 0.155f + ), + < 0.790f => Vector3.Lerp( + new(0, 128, 128), + new(0, 0, 128), + (interp - 0.630f) / 0.16f + ), + < 0.945f => Vector3.Lerp( + new(0, 0, 128), + new(64, 0, 64), + (interp - 0.790f) / 0.155f + ), + _ => new(64, 0, 64), }; } // Period is twice as fast so we oscillate at twice that speed @@ -285,7 +327,7 @@ internal static class ConditionUtils Condition.Pliant => Vector3.Lerp(new(0, 150, 0), new(0, 249, 0), interp), Condition.Primed => Vector3.Lerp(new(-30, -255, 50), new(29, -156, 199), interp), Condition.GoodOmen => Vector3.Lerp(new(100, 20, 0), new(100, 99, 99), interp), - _ => default + _ => default, }; } @@ -294,7 +336,9 @@ internal static class ConditionUtils public static Vector4 GetColor(this Condition me, TimeSpan time) { - return me.GetColor((float)(time.TotalSeconds % ConditionCyclePeriod / ConditionCyclePeriod)); + return me.GetColor( + (float)(time.TotalSeconds % ConditionCyclePeriod / ConditionCyclePeriod) + ); } public static string Name(this Condition me) => @@ -310,7 +354,11 @@ internal static class ConditionUtils foreach (var payload in text) { if (payload is { Type: ReadOnlySePayloadType.Macro, MacroCode: MacroCode.Float }) - finalText += new ReadOnlySePayload(ReadOnlySePayloadType.Text, default, Encoding.UTF8.GetBytes(isRelic ? "1.75" : "1.5")); + finalText += new ReadOnlySePayload( + ReadOnlySePayloadType.Text, + default, + Encoding.UTF8.GetBytes(isRelic ? "1.75" : "1.5") + ); else finalText += payload; } diff --git a/Craftimizer/Utils/AttributeCommandManager.cs b/Craftimizer/Utils/AttributeCommandManager.cs index 2316f92..5cdc334 100644 --- a/Craftimizer/Utils/AttributeCommandManager.cs +++ b/Craftimizer/Utils/AttributeCommandManager.cs @@ -1,13 +1,18 @@ -using Craftimizer.Plugin; -using Dalamud.Game.Command; using System; using System.Collections.Generic; using System.Reflection; +using Craftimizer.Plugin; +using Dalamud.Game.Command; namespace Craftimizer.Utils; [AttributeUsage(AttributeTargets.Method)] -public sealed class CommandAttribute(string name, string description, bool hidden = false, params string[] aliases) : Attribute +public sealed class CommandAttribute( + string name, + string description, + bool hidden = false, + params string[] aliases +) : Attribute { public string Name { get; } = name; public string Description { get; } = description; @@ -22,7 +27,11 @@ public sealed class AttributeCommandManager : IDisposable public AttributeCommandManager() { var target = Service.Plugin; - foreach (var method in target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + foreach ( + var method in target + .GetType() + .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + ) { if (method.GetCustomAttribute() is not { } command) continue; @@ -51,15 +60,21 @@ public sealed class AttributeCommandManager : IDisposable }; if (!RegisteredCommands.Add(command.Name)) - throw new InvalidOperationException($"Command '{command.Name}' is already registered."); + throw new InvalidOperationException( + $"Command '{command.Name}' is already registered." + ); if (!Service.CommandManager.AddHandler(command.Name, info)) - throw new InvalidOperationException($"Failed to register command '{command.Name}'."); + throw new InvalidOperationException( + $"Failed to register command '{command.Name}'." + ); foreach (var alias in command.Aliases) { if (!RegisteredCommands.Add(alias)) - throw new InvalidOperationException($"Command '{alias}' is already registered."); + throw new InvalidOperationException( + $"Command '{alias}' is already registered." + ); if (!Service.CommandManager.AddHandler(alias, aliasInfo)) throw new InvalidOperationException($"Failed to register command '{alias}'."); diff --git a/Craftimizer/Utils/BackgroundTask.cs b/Craftimizer/Utils/BackgroundTask.cs index 69c56d9..4d8341b 100644 --- a/Craftimizer/Utils/BackgroundTask.cs +++ b/Craftimizer/Utils/BackgroundTask.cs @@ -4,7 +4,8 @@ using System.Threading.Tasks; namespace Craftimizer.Utils; -public sealed class BackgroundTask(Func func) : IDisposable where T : struct +public sealed class BackgroundTask(Func func) : IDisposable + where T : struct { public T? Result { get; private set; } public Exception? Exception { get; private set; } @@ -19,26 +20,28 @@ public sealed class BackgroundTask(Func func) : IDispos var token = TokenSource.Token; var task = Task.Run(() => Result = Func(token), token); _ = task.ContinueWith(t => Completed = true); - _ = task.ContinueWith(t => - { - if (token.IsCancellationRequested) - return; + _ = task.ContinueWith( + t => + { + if (token.IsCancellationRequested) + return; - try - { - t.Exception!.Flatten().Handle(ex => ex is TaskCanceledException or OperationCanceledException); - } - catch (AggregateException e) - { - Exception = e; - Log.Error(e, "Background task failed"); - } - }, TaskContinuationOptions.OnlyOnFaulted); + try + { + t.Exception!.Flatten() + .Handle(ex => ex is TaskCanceledException or OperationCanceledException); + } + catch (AggregateException e) + { + Exception = e; + Log.Error(e, "Background task failed"); + } + }, + TaskContinuationOptions.OnlyOnFaulted + ); } - public void Cancel() => - TokenSource.Cancel(); + public void Cancel() => TokenSource.Cancel(); - public void Dispose() => - Cancel(); + public void Dispose() => Cancel(); } diff --git a/Craftimizer/Utils/CSRecipeNote.cs b/Craftimizer/Utils/CSRecipeNote.cs index 8a1988c..75fd7dc 100644 --- a/Craftimizer/Utils/CSRecipeNote.cs +++ b/Craftimizer/Utils/CSRecipeNote.cs @@ -1,13 +1,14 @@ +using System.Runtime.InteropServices; using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.System.String; -using System.Runtime.InteropServices; namespace Craftimizer.Utils; [StructLayout(LayoutKind.Explicit, Size = 2880)] public unsafe struct CSRecipeNote { - [FieldOffset(0x118)] public ushort ActiveCraftRecipeId; + [FieldOffset(0x118)] + public ushort ActiveCraftRecipeId; public static CSRecipeNote* Instance() { diff --git a/Craftimizer/Utils/Chat.cs b/Craftimizer/Utils/Chat.cs index 0bb5970..eb08b5b 100644 --- a/Craftimizer/Utils/Chat.cs +++ b/Craftimizer/Utils/Chat.cs @@ -1,6 +1,6 @@ +using System; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; -using System; namespace Craftimizer.Utils; @@ -19,16 +19,28 @@ public static unsafe class Chat var unsanitizedLength = str->Length; str->SanitizeString( - AllowedEntities.Unknown9 | // 200 - AllowedEntities.Payloads | // 40 - AllowedEntities.OtherCharacters | // 20 - AllowedEntities.CharacterList | // 10 - AllowedEntities.SpecialCharacters | // 8 - AllowedEntities.Numbers | // 4 - AllowedEntities.LowercaseLetters | // 2 - AllowedEntities.UppercaseLetters, // 1 - null); - ArgumentOutOfRangeException.ThrowIfNotEqual(unsanitizedLength, str->Length, nameof(message)); + AllowedEntities.Unknown9 + | // 200 + AllowedEntities.Payloads + | // 40 + AllowedEntities.OtherCharacters + | // 20 + AllowedEntities.CharacterList + | // 10 + AllowedEntities.SpecialCharacters + | // 8 + AllowedEntities.Numbers + | // 4 + AllowedEntities.LowercaseLetters + | // 2 + AllowedEntities.UppercaseLetters, // 1 + null + ); + ArgumentOutOfRangeException.ThrowIfNotEqual( + unsanitizedLength, + str->Length, + nameof(message) + ); UIModule.Instance()->ProcessChatBoxEntry(str); } diff --git a/Craftimizer/Utils/Colors.cs b/Craftimizer/Utils/Colors.cs index a64c088..8b51951 100644 --- a/Craftimizer/Utils/Colors.cs +++ b/Craftimizer/Utils/Colors.cs @@ -1,8 +1,8 @@ -using Craftimizer.Plugin; -using Dalamud.Interface.Colors; -using Dalamud.Bindings.ImGui; using System; using System.Numerics; +using Craftimizer.Plugin; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Colors; namespace Craftimizer.Utils; @@ -15,7 +15,8 @@ public static class Colors public static readonly Vector4 Collectability = new(0.99f, 0.56f, 0.57f, 1f); public static readonly Vector4 CP = new(0.63f, 0.37f, 0.75f, 1f); - private static Vector4 SolverProgressBg => ImGui.ColorConvertU32ToFloat4(ImGui.GetColorU32(ImGuiCol.TableBorderLight)); + private static Vector4 SolverProgressBg => + ImGui.ColorConvertU32ToFloat4(ImGui.GetColorU32(ImGuiCol.TableBorderLight)); private static Vector4 SolverProgressFgBland => ImGuiColors.DalamudWhite2; private static readonly Vector4[] SolverProgressFgColorful = @@ -52,7 +53,7 @@ public static class Colors { Configuration.ProgressBarType.Colorful => SolverProgressFgColorful, Configuration.ProgressBarType.Simple => SolverProgressFgMonochromatic, - _ => throw new InvalidOperationException("No progress bar should be visible") + _ => throw new InvalidOperationException("No progress bar should be visible"), }; if (stageValue is not { } stage) diff --git a/Craftimizer/Utils/CommunityMacros.cs b/Craftimizer/Utils/CommunityMacros.cs index df26458..4f3ea95 100644 --- a/Craftimizer/Utils/CommunityMacros.cs +++ b/Craftimizer/Utils/CommunityMacros.cs @@ -1,18 +1,18 @@ -using Dalamud.Networking.Http; using System; using System.Collections.Generic; -using System.Net.Http; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using System.Text.Json.Serialization; -using System.Net.Http.Json; -using System.Text.Json; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Craftimizer.Simulator.Actions; +using System.Net; +using System.Net.Http; +using System.Net.Http.Json; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; using Craftimizer.Simulator; +using Craftimizer.Simulator.Actions; using Craftimizer.Solver; +using Dalamud.Networking.Http; namespace Craftimizer.Utils; @@ -40,7 +40,9 @@ public sealed class CommunityMacros { [JsonPropertyName("integerValue")] [JsonRequired] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + [JsonNumberHandling( + JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString + )] public required int Value { get; set; } public static implicit operator int(IntegerValue v) => v.Value; @@ -59,6 +61,7 @@ public sealed class CommunityMacros public required ValueData Data { get; set; } public T Value => Data.Fields; + public static implicit operator T(MapValue v) => v.Value; } @@ -74,6 +77,7 @@ public sealed class CommunityMacros public required ValueData Data { get; set; } public T[] Value => Data.Values ?? []; + public static implicit operator T[](ArrayValue v) => v.Value; } @@ -88,8 +92,10 @@ public sealed class CommunityMacros { [JsonRequired] public required List From { get; set; } + [JsonRequired] public required Filter Where { get; set; } + [JsonRequired] public required List OrderBy { get; set; } } @@ -109,6 +115,7 @@ public sealed class CommunityMacros { [JsonRequired] public required List Filters { get; set; } + [JsonRequired] public required CompositeOperator Op { get; set; } } @@ -117,13 +124,14 @@ public sealed class CommunityMacros { OPERATOR_UNSPECIFIED, AND, - OR + OR, } public sealed record FieldFilter { [JsonRequired] public required FieldReference Field { get; set; } + [JsonRequired] public required FieldOperator Op { get; set; } public object? Value { get; set; } @@ -141,13 +149,14 @@ public sealed class CommunityMacros ARRAY_CONTAINS, IN, ARRAY_CONTAINS_ANY, - NOT_IN + NOT_IN, } public sealed record Order { [JsonRequired] public required FieldReference Field { get; set; } + [JsonRequired] public required Direction Direction { get; set; } } @@ -162,7 +171,7 @@ public sealed class CommunityMacros { DIRECTION_UNSPECIFIED, ASCENDING, - DESCENDING + DESCENDING, } private sealed record RunQueryRequest @@ -178,6 +187,7 @@ public sealed class CommunityMacros [JsonRequired] [JsonPropertyName("rlvl")] public required IntegerValue RLvl { get; set; } + [JsonRequired] public required IntegerValue Durability { get; set; } } @@ -185,6 +195,7 @@ public sealed class CommunityMacros public sealed record FieldData { public StringValue? Name { get; set; } + [JsonRequired] public required ArrayValue Rotation { get; set; } public MapValue? Recipe { get; set; } @@ -212,6 +223,7 @@ public sealed class CommunityMacros public string? Slug { get; set; } public string? Version { get; set; } public string? Job { get; set; } + [JsonPropertyName("job_level")] public int JobLevel { get; set; } public int Craftsmanship { get; set; } @@ -219,11 +231,14 @@ public sealed class CommunityMacros public int CP { get; set; } public string? Food { get; set; } public string? Potion { get; set; } + [JsonPropertyName("recipe_job_level")] public int RecipeJobLevel { get; set; } public string? Recipe { get; set; } + // HqIngredients public string? Actions { get; set; } + [JsonPropertyName("created_at")] public long CreatedAt { get; set; } public string? Error { get; set; } @@ -241,10 +256,13 @@ public sealed class CommunityMacros throw new Exception($"Internal error; No fields were returned"); // https://github.com/ffxiv-teamcraft/ffxiv-teamcraft/blob/67f453041c6b2b31d32fcf6e1fd53aa38ed7a12b/apps/client/src/app/model/other/crafting-rotation.ts#L49 - Name = rotation.Name?.Value ?? - (rotation.Recipe is { Value: var recipe } ? - $"rlvl{recipe.RLvl.Value} - {rotation.Rotation.Value.Length} steps, {recipe.Durability.Value} dur" : - "New Teamcraft Rotation"); + Name = + rotation.Name?.Value + ?? ( + rotation.Recipe is { Value: var recipe } + ? $"rlvl{recipe.RLvl.Value} - {rotation.Rotation.Value.Length} steps, {recipe.Durability.Value} dur" + : "New Teamcraft Rotation" + ); var actions = new List(); foreach (var action in rotation.Rotation.Value) @@ -290,7 +308,7 @@ public sealed class CommunityMacros "RemoveFinalAppraisal" => null, // Old actions? - _ => null + _ => null, }; if (actionType.HasValue) actions.Add(actionType.Value); @@ -353,7 +371,7 @@ public sealed class CommunityMacros "DelicateSynthesisTraited" => ActionType.DelicateSynthesis, // Old actions? - _ => null + _ => null, }; if (actionType.HasValue) actions.Add(actionType.Value); @@ -361,16 +379,30 @@ public sealed class CommunityMacros Actions = actions; } - public (float Score, SimulationState FinalState) CalculateScore(SimulatorNoRandom simulator, in SimulationState startingState, in MCTSConfig mctsConfig) + public (float Score, SimulationState FinalState) CalculateScore( + SimulatorNoRandom simulator, + in SimulationState startingState, + in MCTSConfig mctsConfig + ) { return CalculateScore(Actions, simulator, startingState, mctsConfig); } - public static (float Score, SimulationState FinalState) CalculateScore(IReadOnlyCollection actions, SimulatorNoRandom simulator, in SimulationState startingState, in MCTSConfig mctsConfig) + public static (float Score, SimulationState FinalState) CalculateScore( + IReadOnlyCollection actions, + SimulatorNoRandom simulator, + in SimulationState startingState, + in MCTSConfig mctsConfig + ) { var (resp, outState, failedIdx) = simulator.ExecuteMultiple(startingState, actions); outState.ActionCount = actions.Count; - var score = SimulationNode.CalculateScoreForState(outState, simulator.CompletionState, mctsConfig) ?? 0; + var score = + SimulationNode.CalculateScoreForState( + outState, + simulator.CompletionState, + mctsConfig + ) ?? 0; if (resp != ActionResponse.SimulationComplete) { if (failedIdx != -1) @@ -382,7 +414,10 @@ public sealed class CommunityMacros private Dictionary> CachedRotations { get; } = []; - public async Task> RetrieveRotations(int rlvl, CancellationToken token) + public async Task> RetrieveRotations( + int rlvl, + CancellationToken token + ) { lock (CachedRotations) { @@ -397,23 +432,25 @@ public sealed class CommunityMacros return macros; } - private static async Task> RetrieveRotationsInternal(int rlvl, CancellationToken token) + private static async Task> RetrieveRotationsInternal( + int rlvl, + CancellationToken token + ) { using var heCallback = new HappyEyeballsCallback(); - using var client = new HttpClient(new SocketsHttpHandler - { - AutomaticDecompression = DecompressionMethods.All, - ConnectCallback = heCallback.ConnectCallback, - }); + using var client = new HttpClient( + new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.All, + ConnectCallback = heCallback.ConnectCallback, + } + ); var request = new RunQueryRequest { StructuredQuery = new StructuredQuery { - From = - [ - new() { CollectionId = "rotations" } - ], + From = [new() { CollectionId = "rotations" }], Where = new Filter { CompositeFilter = new CompositeFilter @@ -427,8 +464,8 @@ public sealed class CommunityMacros { Field = new FieldReference { FieldPath = "public" }, Op = FieldOperator.EQUAL, - Value = new BooleanValue { Value = true } - } + Value = new BooleanValue { Value = true }, + }, }, new() { @@ -436,10 +473,10 @@ public sealed class CommunityMacros { Field = new FieldReference { FieldPath = "community.rlvl" }, Op = FieldOperator.EQUAL, - Value = new IntegerValue { Value = rlvl } - } - } - ] + Value = new IntegerValue { Value = rlvl }, + }, + }, + ], }, }, OrderBy = @@ -447,39 +484,50 @@ public sealed class CommunityMacros new() { Field = new FieldReference { FieldPath = "xivVersion" }, - Direction = Direction.DESCENDING + Direction = Direction.DESCENDING, }, new() { Field = new FieldReference { FieldPath = "__name__" }, - Direction = Direction.DESCENDING - } - ] + Direction = Direction.DESCENDING, + }, + ], }, }; var resp = await PostFromJsonAsync>( - client, - $"https://firestore.googleapis.com/v1beta1/projects/ffxivteamcraft/databases/(default)/documents:runQuery", - request, new JsonSerializerOptions - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }, token). - ConfigureAwait(false); + client, + $"https://firestore.googleapis.com/v1beta1/projects/ffxivteamcraft/databases/(default)/documents:runQuery", + request, + new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }, + token + ) + .ConfigureAwait(false); if (resp is null) throw new Exception("Internal server error; failed to retrieve macro"); - foreach(var macro in resp) + foreach (var macro in resp) { if (macro.Error is { } error) throw new Exception($"Internal server error ({error.Status}); {error.Message}"); } - return resp.Where(macro => macro.Document is not null).Select(macro => macro.Document!).ToList(); + return resp.Where(macro => macro.Document is not null) + .Select(macro => macro.Document!) + .ToList(); } - private static async Task PostFromJsonAsync(HttpClient client, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, TRequest value, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) + private static async Task PostFromJsonAsync( + HttpClient client, + [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, + TRequest value, + JsonSerializerOptions? options = null, + CancellationToken cancellationToken = default + ) { ArgumentNullException.ThrowIfNull(client); @@ -487,6 +535,8 @@ public sealed class CommunityMacros using var message = await resp.ConfigureAwait(false); message.EnsureSuccessStatusCode(); - return await message.Content!.ReadFromJsonAsync(options, cancellationToken).ConfigureAwait(false); + return await message + .Content!.ReadFromJsonAsync(options, cancellationToken) + .ConfigureAwait(false); } } diff --git a/Craftimizer/Utils/CraftimizerConflictDetector.cs b/Craftimizer/Utils/CraftimizerConflictDetector.cs index b6393d9..b5eb447 100644 --- a/Craftimizer/Utils/CraftimizerConflictDetector.cs +++ b/Craftimizer/Utils/CraftimizerConflictDetector.cs @@ -18,10 +18,10 @@ internal static class CraftimizerConflictDetector throw new System.InvalidOperationException( "Forgeimizer cannot load while the upstream Craftimizer plugin is active.\n\n" - + "Both plugins register the same Dalamud hooks (UseAction, IsActionHighlighted) " - + "and would conflict if loaded together.\n\n" - + "Action: open /xlplugins, disable the upstream 'Craftimizer' plugin, " - + "then re-enable Forgeimizer." + + "Both plugins register the same Dalamud hooks (UseAction, IsActionHighlighted) " + + "and would conflict if loaded together.\n\n" + + "Action: open /xlplugins, disable the upstream 'Craftimizer' plugin, " + + "then re-enable Forgeimizer." ); } } diff --git a/Craftimizer/Utils/DynamicBars.cs b/Craftimizer/Utils/DynamicBars.cs index a0c2181..9028af3 100644 --- a/Craftimizer/Utils/DynamicBars.cs +++ b/Craftimizer/Utils/DynamicBars.cs @@ -1,28 +1,34 @@ -using Craftimizer.Plugin; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; -using System.Collections.Generic; using System; -using System.Numerics; +using System.Collections.Generic; using System.Linq; -using Dalamud.Utility.Numerics; +using System.Numerics; +using Craftimizer.Plugin; +using Dalamud.Bindings.ImGui; using Dalamud.Interface; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Utility.Numerics; namespace Craftimizer.Utils; internal static class DynamicBars { - public readonly record struct BarData(string Name, Vector4 Color, SimulatedMacro.Reliablity.Param? Reliability, float Value, float Max, IReadOnlyList? Collectability = null, string? Caption = null, string? DefaultCaptionSizeText = null, Action? CustomDrawer = null) + public readonly record struct BarData( + string Name, + Vector4 Color, + SimulatedMacro.Reliablity.Param? Reliability, + float Value, + float Max, + IReadOnlyList? Collectability = null, + string? Caption = null, + string? DefaultCaptionSizeText = null, + Action? CustomDrawer = null + ) { - public BarData(string name, Action customDrawer) : this(name, default, null, 0, 0, null, null, null, customDrawer) - { + public BarData(string name, Action customDrawer) + : this(name, default, null, 0, 0, null, null, null, customDrawer) { } - } - - public BarData(string name, Vector4 color, float value, float max) : this(name, color, null, value, max, null, null, null) - { - - } + public BarData(string name, Vector4 color, float value, float max) + : this(name, color, null, value, max, null, null, null) { } } public readonly record struct DrawerParams(float TotalSize, float Spacing); @@ -39,13 +45,19 @@ internal static class DynamicBars return Math.Max(ImGui.CalcTextSize(caption).X, defaultSize); // max (sp/2) "/" (sp/2) max return Math.Max( - Math.Max(ImGui.CalcTextSize($"{b.Value:0}").X, ImGui.CalcTextSize($"{b.Max:0}").X) * 2 - + ImGui.GetStyle().ItemSpacing.X - + ImGui.CalcTextSize("/").X, - defaultSize); + Math.Max(ImGui.CalcTextSize($"{b.Value:0}").X, ImGui.CalcTextSize($"{b.Max:0}").X) + * 2 + + ImGui.GetStyle().ItemSpacing.X + + ImGui.CalcTextSize("/").X, + defaultSize + ); }); - private static ImRaii.ColorDisposable? PushCollectableColor(this in BarData bar, float collectability, bool colorUnmetThreshold = true) + private static ImRaii.ColorDisposable? PushCollectableColor( + this in BarData bar, + float collectability, + bool colorUnmetThreshold = true + ) { if (bar.Collectability is not { } collectabilities) return null; @@ -88,7 +100,10 @@ internal static class DynamicBars var pos = ImGui.GetCursorPos(); var screenPos = ImGui.GetCursorScreenPos(); using (var color = ImRaii.PushColor(ImGuiCol.PlotHistogram, bar.Color)) - ImGuiUtils.ProgressBar(Math.Clamp(bar.Value / bar.Max, 0, 1), new(barSize, ImGui.GetFrameHeight())); + ImGuiUtils.ProgressBar( + Math.Clamp(bar.Value / bar.Max, 0, 1), + new(barSize, ImGui.GetFrameHeight()) + ); if (bar.Collectability is { } collectability) { var i = 0; @@ -101,27 +116,36 @@ internal static class DynamicBars continue; var offset = barSize * threshold / bar.Max; var isLast = i == collectability.Count; - var offsetNext = isLast ? barSize : barSize * collectability[i]!.Value / bar.Max; + var offsetNext = isLast + ? barSize + : barSize * collectability[i]!.Value / bar.Max; var passedThreshold = bar.Value >= threshold; - ImGui.GetWindowDrawList().AddRectFilled( - screenPos + new Vector2(offset, 0), - screenPos + new Vector2(offsetNext, height), - ImGui.GetColorU32(color.WithW(passedThreshold ? 0.6f : 0.2f)), - isLast ? rounding : 0 - ); - ImGui.GetWindowDrawList().AddLine( - screenPos + new Vector2(offset, 0), - screenPos + new Vector2(offset, height), - ImGui.GetColorU32(color), - Math.Max(passedThreshold ? 3 : 1.5f, rounding / 2f) - ); + ImGui + .GetWindowDrawList() + .AddRectFilled( + screenPos + new Vector2(offset, 0), + screenPos + new Vector2(offsetNext, height), + ImGui.GetColorU32(color.WithW(passedThreshold ? 0.6f : 0.2f)), + isLast ? rounding : 0 + ); + ImGui + .GetWindowDrawList() + .AddLine( + screenPos + new Vector2(offset, 0), + screenPos + new Vector2(offset, height), + ImGui.GetColorU32(color), + Math.Max(passedThreshold ? 3 : 1.5f, rounding / 2f) + ); } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenOverlapped)) { if (bar.Reliability is { } reliability) { - if (reliability.GetViolinData(bar.Max, (int)(barSize / 5), 0.02) is { } violinData) + if ( + reliability.GetViolinData(bar.Max, (int)(barSize / 5), 0.02) is + { } violinData + ) { ImGui.SetCursorPos(pos); ImGuiUtils.ViolinPlot(violinData, new(barSize, ImGui.GetFrameHeight())); @@ -129,7 +153,10 @@ internal static class DynamicBars { using var _font = ImRaii.PushFont(UiBuilder.DefaultFont); using var _tooltip = ImRaii.Tooltip(); - using var _ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); + using var _ = ImRaii.PushStyle( + ImGuiStyleVar.ItemSpacing, + Vector2.Zero + ); ImGui.TextUnformatted("Min: "); ImGui.SameLine(0, 0); @@ -221,7 +248,8 @@ internal static class DynamicBars { tooltip = $"Solver Progress: {solver.ProgressValue:N0} / {solver.ProgressMax:N0}"; if (solver.ProgressValue > solver.ProgressMax) - tooltip += $"\n\nThis is taking longer than expected. Check to see if your gear stats are good and the solver settings are adequate."; + tooltip += + $"\n\nThis is taking longer than expected. Check to see if your gear stats are good and the solver settings are adequate."; } ImGuiUtils.TooltipWrapped(tooltip); } diff --git a/Craftimizer/Utils/FoodStatus.cs b/Craftimizer/Utils/FoodStatus.cs index 3683741..b429f1b 100644 --- a/Craftimizer/Utils/FoodStatus.cs +++ b/Craftimizer/Utils/FoodStatus.cs @@ -1,9 +1,9 @@ -using Craftimizer.Plugin; -using Lumina.Excel.Sheets; using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Craftimizer.Plugin; +using Lumina.Excel.Sheets; namespace Craftimizer.Utils; @@ -15,8 +15,20 @@ public static class FoodStatus private static readonly ImmutableArray FoodOrder; private static readonly ImmutableArray MedicineOrder; - public readonly record struct FoodStat(bool IsRelative, int Value, int Max, int ValueHQ, int MaxHQ); - public readonly record struct Food(Item Item, FoodStat? Craftsmanship, FoodStat? Control, FoodStat? CP); + public readonly record struct FoodStat( + bool IsRelative, + int Value, + int Max, + int ValueHQ, + int MaxHQ + ); + + public readonly record struct Food( + Item Item, + FoodStat? Craftsmanship, + FoodStat? Control, + FoodStat? CP + ); static FoodStatus() { @@ -39,18 +51,33 @@ public static class FoodStatus if (LuminaSheets.ItemFoodSheet.GetRowOrDefault(itemAction.Data[1]) is not { } itemFood) continue; - FoodStat? craftsmanship = null, control = null, cp = null; + FoodStat? craftsmanship = null, + control = null, + cp = null; foreach (var stat in itemFood.Params) { if (stat.BaseParam.RowId == 0) continue; - var foodStat = new FoodStat(stat.IsRelative, stat.Value, stat.Max, stat.ValueHQ, stat.MaxHQ); + var foodStat = new FoodStat( + stat.IsRelative, + stat.Value, + stat.Max, + stat.ValueHQ, + stat.MaxHQ + ); switch (stat.BaseParam.RowId) { - case Gearsets.ParamCraftsmanship: craftsmanship = foodStat; break; - case Gearsets.ParamControl: control = foodStat; break; - case Gearsets.ParamCP: cp = foodStat; break; - default: continue; + case Gearsets.ParamCraftsmanship: + craftsmanship = foodStat; + break; + case Gearsets.ParamControl: + control = foodStat; + break; + case Gearsets.ParamCP: + cp = foodStat; + break; + default: + continue; } } @@ -70,14 +97,23 @@ public static class FoodStatus FoodItems = foods.ToFrozenDictionary(); MedicineItems = medicines.ToFrozenDictionary(); - FoodOrder = [.. FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key)]; - MedicineOrder = [.. MedicineItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key)]; + FoodOrder = + [ + .. FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key), + ]; + MedicineOrder = + [ + .. MedicineItems + .OrderByDescending(a => a.Value.Item.LevelItem.RowId) + .Select(a => a.Key), + ]; } public static void Initialize() { } public static IEnumerable OrderedFoods => FoodOrder.Select(id => FoodItems[id]); - public static IEnumerable OrderedMedicines => MedicineOrder.Select(id => MedicineItems[id]); + public static IEnumerable OrderedMedicines => + MedicineOrder.Select(id => MedicineItems[id]); public static (uint ItemId, bool IsHQ)? ResolveFoodParam(ushort param) { diff --git a/Craftimizer/Utils/FuzzyMatcher.cs b/Craftimizer/Utils/FuzzyMatcher.cs index 00913ef..060e5e9 100644 --- a/Craftimizer/Utils/FuzzyMatcher.cs +++ b/Craftimizer/Utils/FuzzyMatcher.cs @@ -24,7 +24,11 @@ internal readonly struct FuzzyMatcher { MatchMode.FuzzyParts => FindNeedleSegments(needleString), MatchMode.Fuzzy or MatchMode.Simple => EmptySegArray, - _ => throw new ArgumentOutOfRangeException(nameof(matchMode), matchMode, "Invalid match mode"), + _ => throw new ArgumentOutOfRangeException( + nameof(matchMode), + matchMode, + "Invalid match mode" + ), }; } @@ -59,7 +63,9 @@ internal readonly struct FuzzyMatcher return 0; if (mode == MatchMode.Simple) - return value.Contains(needleString, StringComparison.InvariantCultureIgnoreCase) ? 1 : 0; + return value.Contains(needleString, StringComparison.InvariantCultureIgnoreCase) + ? 1 + : 0; if (mode == MatchMode.Fuzzy) return GetRawScore(value, 0, needleFinalPosition); @@ -101,7 +107,11 @@ internal readonly struct FuzzyMatcher private int GetRawScore(ReadOnlySpan haystack, int needleStart, int needleEnd) { - var (startPos, gaps, consecutive, borderMatches, endPos) = FindForward(haystack, needleStart, needleEnd); + var (startPos, gaps, consecutive, borderMatches, endPos) = FindForward( + haystack, + needleStart, + needleEnd + ); if (startPos < 0) return 0; @@ -109,28 +119,40 @@ internal readonly struct FuzzyMatcher var score = CalculateRawScore(needleSize, startPos, gaps, consecutive, borderMatches); - (startPos, gaps, consecutive, borderMatches) = FindReverse(haystack, endPos, needleStart, needleEnd); + (startPos, gaps, consecutive, borderMatches) = FindReverse( + haystack, + endPos, + needleStart, + needleEnd + ); var revScore = CalculateRawScore(needleSize, startPos, gaps, consecutive, borderMatches); return int.Max(score, revScore); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int CalculateRawScore(int needleSize, int startPos, int gaps, int consecutive, int borderMatches) + private static int CalculateRawScore( + int needleSize, + int startPos, + int gaps, + int consecutive, + int borderMatches + ) { - var score = 100 - + needleSize * 3 - + borderMatches * 3 - + consecutive * 5 - - startPos - - gaps * 2; + var score = + 100 + needleSize * 3 + borderMatches * 3 + consecutive * 5 - startPos - gaps * 2; if (startPos == 0) score += 5; return score < 1 ? 1 : score; } - private (int StartPos, int Gaps, int Consecutive, int BorderMatches, int HaystackIndex) FindForward( - ReadOnlySpan haystack, int needleStart, int needleEnd) + private ( + int StartPos, + int Gaps, + int Consecutive, + int BorderMatches, + int HaystackIndex + ) FindForward(ReadOnlySpan haystack, int needleStart, int needleEnd) { var needleIndex = needleStart; var lastMatchIndex = -10; @@ -176,7 +198,11 @@ internal readonly struct FuzzyMatcher } private (int StartPos, int Gaps, int Consecutive, int BorderMatches) FindReverse( - ReadOnlySpan haystack, int haystackLastMatchIndex, int needleStart, int needleEnd) + ReadOnlySpan haystack, + int haystackLastMatchIndex, + int needleStart, + int needleEnd + ) { var needleIndex = needleEnd; var revLastMatchIndex = haystack.Length + 10; diff --git a/Craftimizer/Utils/Gearsets.cs b/Craftimizer/Utils/Gearsets.cs index 09a892d..e0a054c 100644 --- a/Craftimizer/Utils/Gearsets.cs +++ b/Craftimizer/Utils/Gearsets.cs @@ -1,18 +1,20 @@ +using System; +using System.Linq; +using Craftimizer.Plugin; using Craftimizer.Simulator; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using Lumina.Excel.Sheets; -using System; -using System.Linq; -using Craftimizer.Plugin; namespace Craftimizer.Utils; public static unsafe class Gearsets { public record struct GearsetStats(int CP, int Craftsmanship, int Control); + public record struct GearsetMateria(ushort Type, ushort Grade); + public record struct GearsetItem(uint ItemId, bool IsHq, GearsetMateria[] Materia); private static readonly GearsetStats BaseStats = new(180, 0, 0); @@ -27,7 +29,11 @@ public static unsafe class Gearsets for (var i = 0; i < container->Size; ++i) { var item = container->Items[i]; - items[i] = new(item.ItemId, item.Flags.HasFlag(InventoryItem.ItemFlags.HighQuality), GetMaterias(item.Materia, item.MateriaGrades)); + items[i] = new( + item.ItemId, + item.Flags.HasFlag(InventoryItem.ItemFlags.HighQuality), + GetMaterias(item.Materia, item.MateriaGrades) + ); } return items; } @@ -39,7 +45,11 @@ public static unsafe class Gearsets for (var i = 0; i < 14; ++i) { var item = gearsetItems[i]; - items[i] = new(item.ItemId % 1000000, item.ItemId > 1000000, GetMaterias(item.Materia, item.MateriaGrades)); + items[i] = new( + item.ItemId % 1000000, + item.ItemId > 1000000, + GetMaterias(item.Materia, item.MateriaGrades) + ); } return items; } @@ -48,7 +58,9 @@ public static unsafe class Gearsets { var item = LuminaSheets.ItemSheet.GetRow(gearsetItem.ItemId)!; - int cp = 0, craftsmanship = 0, control = 0; + int cp = 0, + craftsmanship = 0, + control = 0; void IncreaseStat(uint baseParam, int amount) { @@ -83,7 +95,12 @@ public static unsafe class Gearsets } public static GearsetStats CalculateGearsetStats(GearsetItem[] gearsetItems) => - gearsetItems.Select(CalculateGearsetItemStats).Aggregate(BaseStats, (a, b) => new(a.CP + b.CP, a.Craftsmanship + b.Craftsmanship, a.Control + b.Control)); + gearsetItems + .Select(CalculateGearsetItemStats) + .Aggregate( + BaseStats, + (a, b) => new(a.CP + b.CP, a.Craftsmanship + b.Craftsmanship, a.Control + b.Control) + ); public static GearsetStats CalculateGearsetCurrentStats() { @@ -97,10 +114,24 @@ public static unsafe class Gearsets }; } - public static CharacterStats CalculateCharacterStats(GearsetItem[] gearsetItems, int characterLevel, bool canUseManipulation) => - CalculateCharacterStats(CalculateGearsetStats(gearsetItems), gearsetItems, characterLevel, canUseManipulation); + public static CharacterStats CalculateCharacterStats( + GearsetItem[] gearsetItems, + int characterLevel, + bool canUseManipulation + ) => + CalculateCharacterStats( + CalculateGearsetStats(gearsetItems), + gearsetItems, + characterLevel, + canUseManipulation + ); - public static CharacterStats CalculateCharacterStats(GearsetStats gearsetStats, GearsetItem[] gearsetItems, int characterLevel, bool canUseManipulation) => + public static CharacterStats CalculateCharacterStats( + GearsetStats gearsetStats, + GearsetItem[] gearsetItems, + int characterLevel, + bool canUseManipulation + ) => new() { CP = gearsetStats.CP, @@ -115,8 +146,7 @@ public static unsafe class Gearsets public static bool HasDelineations() => InventoryManager.Instance()->GetInventoryItemCount(28724) > 0; - public static bool IsItem(GearsetItem item, uint itemId) => - item.ItemId == itemId; + public static bool IsItem(GearsetItem item, uint itemId) => item.ItemId == itemId; public static bool IsSpecialistSoulCrystal(GearsetItem item) { @@ -125,11 +155,18 @@ public static unsafe class Gearsets var luminaItem = LuminaSheets.ItemSheet.GetRow(item.ItemId)!; // Soul Crystal ItemUICategory DoH Category - return luminaItem.ItemUICategory.RowId == 62 && luminaItem.ClassJobUse.Value.ClassJobCategory.RowId == 33; + return luminaItem.ItemUICategory.RowId == 62 + && luminaItem.ClassJobUse.Value.ClassJobCategory.RowId == 33; } public static bool IsSplendorousTool(GearsetItem item) => - LuminaSheets.ItemSheetEnglish.GetRow(item.ItemId).Description.ToString().Contains("Increases to quality are 1.75 times higher than normal when material condition is Good.", StringComparison.Ordinal); + LuminaSheets + .ItemSheetEnglish.GetRow(item.ItemId) + .Description.ToString() + .Contains( + "Increases to quality are 1.75 times higher than normal when material condition is Good.", + StringComparison.Ordinal + ); // https://github.com/ffxiv-teamcraft/ffxiv-teamcraft/blob/24d0db2d9676f264edf53651b21005305267c84c/apps/client/src/app/modules/gearsets/materia.service.ts#L265 private static int CalculateParamCap(Item item, uint paramId) @@ -142,14 +179,14 @@ public static unsafe class Gearsets ParamCP => ilvl.CP, ParamCraftsmanship => ilvl.Craftsmanship, ParamControl => ilvl.Control, - _ => 0 + _ => 0, }; // https://github.com/ffxiv-teamcraft/ffxiv-teamcraft/blob/24d0db2d9676f264edf53651b21005305267c84c/apps/data-extraction/src/extractors/items.extractor.ts#L6 var slotMod = item.EquipSlotCategory.RowId switch { 1 => param.OneHandWeaponPercent, // column 4 - 2 => param.OffHandPercent, // column 5 - 3 => param.HeadPercent, // ... + 2 => param.OffHandPercent, // column 5 + 3 => param.HeadPercent, // ... 4 => param.ChestPercent, 5 => param.HandsPercent, 6 => param.WaistPercent, @@ -168,16 +205,20 @@ public static unsafe class Gearsets 19 => param.HeadChestHandsLegsFeetPercent, 20 => param.ChestLegsGlovesPercent, 21 => param.ChestLegsFeetPercent, - _ => 0 + _ => 0, }; var roleMod = param.MeldParam[item.BaseParamModifier]; // https://github.com/Caraxi/SimpleTweaksPlugin/pull/595 - var cap = (int)Math.Round((float)baseValue * slotMod / (roleMod * 10f), MidpointRounding.AwayFromZero); + var cap = (int) + Math.Round((float)baseValue * slotMod / (roleMod * 10f), MidpointRounding.AwayFromZero); return cap == 0 ? int.MaxValue : cap; } - private static GearsetMateria[] GetMaterias(ReadOnlySpan types, ReadOnlySpan grades) + private static GearsetMateria[] GetMaterias( + ReadOnlySpan types, + ReadOnlySpan grades + ) { var materia = new GearsetMateria[5]; for (var i = 0; i < 5; ++i) diff --git a/Craftimizer/Utils/Hooks.cs b/Craftimizer/Utils/Hooks.cs index 03080f4..b9e80ac 100644 --- a/Craftimizer/Utils/Hooks.cs +++ b/Craftimizer/Utils/Hooks.cs @@ -1,7 +1,7 @@ +using System; using Craftimizer.Plugin; using Dalamud.Hooking; using FFXIVClientStructs.FFXIV.Client.Game; -using System; using ActionType = Craftimizer.Simulator.Actions.ActionType; using ActionUtils = Craftimizer.Plugin.ActionUtils; using CSActionType = FFXIVClientStructs.FFXIV.Client.Game.ActionType; @@ -14,33 +14,77 @@ public sealed unsafe class Hooks : IDisposable public event OnActionUsedDelegate? OnActionUsed; - public delegate bool UseActionDelegate(ActionManager* manager, CSActionType actionType, uint actionId, ulong targetId, uint extraParam, ActionManager.UseActionMode mode, uint comboRouteId, bool* outOptAreaTargeted); + public delegate bool UseActionDelegate( + ActionManager* manager, + CSActionType actionType, + uint actionId, + ulong targetId, + uint extraParam, + ActionManager.UseActionMode mode, + uint comboRouteId, + bool* outOptAreaTargeted + ); public readonly Hook UseActionHook = null!; - public delegate byte IsActionHighlightedDelegate(ActionManager* manager, CSActionType actionType, uint actionId); + public delegate byte IsActionHighlightedDelegate( + ActionManager* manager, + CSActionType actionType, + uint actionId + ); public readonly Hook IsActionHighlightedHook = null!; public Hooks() { - UseActionHook = Service.GameInteropProvider.HookFromAddress((nint)ActionManager.MemberFunctionPointers.UseAction, UseActionDetour); - IsActionHighlightedHook = Service.GameInteropProvider.HookFromAddress((nint)ActionManager.MemberFunctionPointers.IsActionHighlighted, IsActionHighlightedDetour); + UseActionHook = Service.GameInteropProvider.HookFromAddress( + (nint)ActionManager.MemberFunctionPointers.UseAction, + UseActionDetour + ); + IsActionHighlightedHook = + Service.GameInteropProvider.HookFromAddress( + (nint)ActionManager.MemberFunctionPointers.IsActionHighlighted, + IsActionHighlightedDetour + ); UseActionHook.Enable(); IsActionHighlightedHook.Enable(); } - private bool UseActionDetour(ActionManager* manager, CSActionType actionType, uint actionId, ulong targetId, uint extraParam, ActionManager.UseActionMode mode, uint comboRouteId, bool* optOutAreaTargeted) + private bool UseActionDetour( + ActionManager* manager, + CSActionType actionType, + uint actionId, + ulong targetId, + uint extraParam, + ActionManager.UseActionMode mode, + uint comboRouteId, + bool* optOutAreaTargeted + ) { var canCast = manager->GetActionStatus(actionType, actionId) == 0; - var ret = UseActionHook.Original(manager, actionType, actionId, targetId, extraParam, mode, comboRouteId, optOutAreaTargeted); + var ret = UseActionHook.Original( + manager, + actionType, + actionId, + targetId, + extraParam, + mode, + comboRouteId, + optOutAreaTargeted + ); if (canCast && ret && actionType is CSActionType.CraftAction or CSActionType.Action) { - var classJob = ClassJobUtils.GetClassJobFromIdx((byte)(Service.Objects.LocalPlayer?.ClassJob.RowId ?? 0)); + var classJob = ClassJobUtils.GetClassJobFromIdx( + (byte)(Service.Objects.LocalPlayer?.ClassJob.RowId ?? 0) + ); if (classJob != null) { - var simActionType = ActionUtils.GetActionTypeFromId(actionId, classJob.Value, actionType == CSActionType.CraftAction); + var simActionType = ActionUtils.GetActionTypeFromId( + actionId, + classJob.Value, + actionType == CSActionType.CraftAction + ); if (simActionType != null) { try @@ -57,7 +101,11 @@ public sealed unsafe class Hooks : IDisposable return ret; } - private byte IsActionHighlightedDetour(ActionManager* manager, CSActionType actionType, uint actionId) + private byte IsActionHighlightedDetour( + ActionManager* manager, + CSActionType actionType, + uint actionId + ) { var ret = IsActionHighlightedHook.Original(manager, actionType, actionId); @@ -83,7 +131,11 @@ public sealed unsafe class Hooks : IDisposable if (classJob == null) return ret; - var simActionType = ActionUtils.GetActionTypeFromId(actionId, classJob.Value, actionType == CSActionType.CraftAction); + var simActionType = ActionUtils.GetActionTypeFromId( + actionId, + classJob.Value, + actionType == CSActionType.CraftAction + ); if (simActionType == null) return ret; diff --git a/Craftimizer/Utils/IconManager.cs b/Craftimizer/Utils/IconManager.cs index e613e34..43479ef 100644 --- a/Craftimizer/Utils/IconManager.cs +++ b/Craftimizer/Utils/IconManager.cs @@ -1,14 +1,14 @@ -using Craftimizer.Plugin; -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Textures; -using Dalamud.Interface.Textures.TextureWraps; -using Dalamud.Utility; using System; using System.Collections.Generic; using System.Numerics; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Craftimizer.Plugin; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; +using Dalamud.Utility; namespace Craftimizer.Utils; @@ -52,7 +52,8 @@ public sealed class IconManager : IDisposable return null; } - public IDalamudTextureWrap GetWrapOrEmpty() => GetWrap() ?? Service.DalamudAssetManager.Empty4X4; + public IDalamudTextureWrap GetWrapOrEmpty() => + GetWrap() ?? Service.DalamudAssetManager.Empty4X4; public void Dispose() { @@ -85,7 +86,10 @@ public sealed class IconManager : IDisposable Service.TextureProvider.GetFromGameIcon(new GameIconLookup(id, itemHq: isHq)); private static ISharedImmediateTexture GetAssemblyTextureInternal(string filename) => - Service.TextureProvider.GetFromManifestResource(Assembly.GetExecutingAssembly(), $"Craftimizer.{filename}"); + Service.TextureProvider.GetFromManifestResource( + Assembly.GetExecutingAssembly(), + $"Craftimizer.{filename}" + ); public static ILoadedTextureIcon GetIcon(uint id, bool isHq = false) => new LoadedIcon(GetIconInternal(id, isHq)); diff --git a/Craftimizer/Utils/Ipc.cs b/Craftimizer/Utils/Ipc.cs index 2367b09..66f10c1 100644 --- a/Craftimizer/Utils/Ipc.cs +++ b/Craftimizer/Utils/Ipc.cs @@ -1,10 +1,10 @@ -using Craftimizer.Plugin; -using Dalamud.Plugin; using System; using System.Reflection; using System.Runtime.CompilerServices; -using DotNext.Reflection; +using Craftimizer.Plugin; +using Dalamud.Plugin; using DotNext.Collections.Generic; +using DotNext.Reflection; namespace Craftimizer.Utils; @@ -39,16 +39,27 @@ public sealed class Ipc var returnsVoid = typeMethod.ReturnType == typeof(void); - var propSubscriber = typeof(IDalamudPluginInterface).GetMethod("GetIpcSubscriber", typeMethod.GetParameters().Length + 1, [typeof(string)]); + var propSubscriber = typeof(IDalamudPluginInterface).GetMethod( + "GetIpcSubscriber", + typeMethod.GetParameters().Length + 1, + [typeof(string)] + ); if (propSubscriber is null) throw new InvalidOperationException("GetIpcSubscriber method not found"); - var callGateSubscriber = propSubscriber.MakeGenericMethod([.. typeMethod.GetParameterTypes(), returnsVoid ? typeof(int) : typeMethod.ReturnType]).Invoke(Service.PluginInterface, [attr.Name ?? prop.Name]); + var callGateSubscriber = propSubscriber + .MakeGenericMethod([ + .. typeMethod.GetParameterTypes(), + returnsVoid ? typeof(int) : typeMethod.ReturnType, + ]) + .Invoke(Service.PluginInterface, [attr.Name ?? prop.Name]); if (callGateSubscriber is null) throw new InvalidOperationException("CallGateSubscriber is null"); - var invokeFunc = callGateSubscriber.GetType().GetMethod(returnsVoid ? "InvokeAction" : "InvokeFunc"); + var invokeFunc = callGateSubscriber + .GetType() + .GetMethod(returnsVoid ? "InvokeAction" : "InvokeFunc"); if (invokeFunc is null) throw new InvalidOperationException("Subscriber Invoke method not found"); @@ -62,7 +73,8 @@ public sealed class Ipc public Func MacroMateIsAvailable { get; private set; } = null!; [IPCCall("MacroMate.CreateOrUpdateMacro")] - public Func MacroMateCreateMacro { get; private set; } = null!; + public Func MacroMateCreateMacro { get; private set; } = + null!; [IPCCall("MacroMate.ValidateGroupPath")] public Func MacroMateValidateGroupPath { get; private set; } = null!; diff --git a/Craftimizer/Utils/Log.cs b/Craftimizer/Utils/Log.cs index e85ccf1..1a1bd13 100644 --- a/Craftimizer/Utils/Log.cs +++ b/Craftimizer/Utils/Log.cs @@ -1,5 +1,5 @@ -using Craftimizer.Plugin; using System; +using Craftimizer.Plugin; namespace Craftimizer.Utils; @@ -8,5 +8,6 @@ public static class Log public static void Debug(string line) => Service.PluginLog.Debug(line); public static void Error(string line) => Service.PluginLog.Error(line); + public static void Error(Exception e, string line) => Service.PluginLog.Error(e, line); } diff --git a/Craftimizer/Utils/MacroCopy.cs b/Craftimizer/Utils/MacroCopy.cs index 6d71503..603d3f4 100644 --- a/Craftimizer/Utils/MacroCopy.cs +++ b/Craftimizer/Utils/MacroCopy.cs @@ -1,13 +1,13 @@ +using System; +using System.Collections.Generic; using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; +using Dalamud.Bindings.ImGui; using Dalamud.Interface.ImGuiNotification; using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Misc; -using Dalamud.Bindings.ImGui; -using System; -using System.Collections.Generic; namespace Craftimizer.Utils; @@ -20,13 +20,15 @@ public static class MacroCopy { if (actions.Count == 0) { - Plugin.Plugin.DisplayNotification(new() - { - Content = "Cannot copy an empty macro.", - MinimizedText = "Cannot copy empty macro", - Title = "Macro Not Copied", - Type = NotificationType.Error - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = "Cannot copy an empty macro.", + MinimizedText = "Cannot copy empty macro", + Title = "Macro Not Copied", + Type = NotificationType.Error, + } + ); return; } @@ -49,9 +51,14 @@ public static class MacroCopy } } - private static List GetMacros(IReadOnlyList actions, MacroCopyConfiguration config) + private static List GetMacros( + IReadOnlyList actions, + MacroCopyConfiguration config + ) { - var mustSplit = (config.Type == MacroCopyConfiguration.CopyType.CopyToMacro || !config.CombineMacro) && config.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate; + var mustSplit = + (config.Type == MacroCopyConfiguration.CopyType.CopyToMacro || !config.CombineMacro) + && config.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate; var macros = new List(); @@ -143,41 +150,54 @@ public static class MacroCopy { var config = Service.Configuration.MacroCopy; - int i, macroIdx; + int i, + macroIdx; for ( i = 0, macroIdx = config.StartMacroIdx; i < macros.Count && i < config.MaxMacroCount && macroIdx < 100; - i++, macroIdx += config.CopyDown ? 10 : 1) + i++, macroIdx += config.CopyDown ? 10 : 1 + ) SetMacro(macroIdx, config.SharedMacro, macros[i], i + 1); if (config.ShowCopiedMessage) { - Plugin.Plugin.DisplayNotification(new() - { - Content = i > 1 ? "Copied macro to User Macros." : $"Copied {i} macros to User Macros.", - MinimizedText = i > 1 ? "Copied macro" : $"Copied {i} macros", - Title = "Macro Copied", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = + i > 1 + ? "Copied macro to User Macros." + : $"Copied {i} macros to User Macros.", + MinimizedText = i > 1 ? "Copied macro" : $"Copied {i} macros", + Title = "Macro Copied", + Type = NotificationType.Success, + } + ); } if (i < macros.Count) { Service.Plugin.OpenMacroClipboard(macros); var rest = macros.Count - i; - Plugin.Plugin.DisplayNotification(new() - { - Content = $"Couldn't copy {rest} macro{(rest == 1 ? "" : "s")}, so a window was opened with all of them.", - Minimized = false, - Title = "Macro Copied", - Type = NotificationType.Warning - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = + $"Couldn't copy {rest} macro{(rest == 1 ? "" : "s")}, so a window was opened with all of them.", + Minimized = false, + Title = "Macro Copied", + Type = NotificationType.Warning, + } + ); } } private static unsafe void SetMacro(int idx, bool isShared, string macroText, int macroIdx) { if (idx >= 100 || idx < 0) - throw new ArgumentOutOfRangeException(nameof(idx), "Macro index must be between 0 and 99"); + throw new ArgumentOutOfRangeException( + nameof(idx), + "Macro index must be between 0 and 99" + ); var set = isShared ? 1u : 0u; @@ -201,13 +221,19 @@ public static class MacroCopy ImGui.SetClipboardText(string.Join(Environment.NewLine + Environment.NewLine, macros)); if (Service.Configuration.MacroCopy.ShowCopiedMessage) { - Plugin.Plugin.DisplayNotification(new() - { - Content = macros.Count == 1 ? "Copied macro to clipboard." : $"Copied {macros.Count} macros to clipboard.", - MinimizedText = macros.Count == 1 ? "Copied macro" : $"Copied {macros.Count} macros", - Title = "Macro Copied", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = + macros.Count == 1 + ? "Copied macro to clipboard." + : $"Copied {macros.Count} macros to clipboard.", + MinimizedText = + macros.Count == 1 ? "Copied macro" : $"Copied {macros.Count} macros", + Title = "Macro Copied", + Type = NotificationType.Success, + } + ); } } @@ -215,13 +241,15 @@ public static class MacroCopy { if (!Service.Ipc.MacroMateIsAvailable()) { - Plugin.Plugin.DisplayNotification(new() - { - Content = "Please check if it installed and enabled.", - MinimizedText = "Macro Mate is unavailable", - Title = "Macro Mate Unavailable", - Type = NotificationType.Error - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = "Please check if it installed and enabled.", + MinimizedText = "Macro Mate is unavailable", + Title = "Macro Mate Unavailable", + Type = NotificationType.Error, + } + ); return; } @@ -232,27 +260,36 @@ public static class MacroCopy var (isValidParent, parentError) = Service.Ipc.MacroMateValidateGroupPath(parentPath); if (!isValidParent) { - Plugin.Plugin.DisplayNotification(new() - { - Content = parentError!, - MinimizedText = parentError, - Title = "Macro Mate Invalid Parent", - Type = NotificationType.Error - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = parentError!, + MinimizedText = parentError, + Title = "Macro Mate Invalid Parent", + Type = NotificationType.Error, + } + ); return; } - Service.Ipc.MacroMateCreateMacro(Service.Configuration.MacroCopy.MacroMateName, macro, parentPath, null); + Service.Ipc.MacroMateCreateMacro( + Service.Configuration.MacroCopy.MacroMateName, + macro, + parentPath, + null + ); if (Service.Configuration.MacroCopy.ShowCopiedMessage) { - Plugin.Plugin.DisplayNotification(new() - { - Content = "Copied macro to Macro Mate.", - MinimizedText = "Copied macro", - Title = "Macro Copied", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = "Copied macro to Macro Mate.", + MinimizedText = "Copied macro", + Title = "Macro Copied", + Type = NotificationType.Success, + } + ); } } } diff --git a/Craftimizer/Utils/MacroImport.cs b/Craftimizer/Utils/MacroImport.cs index f7d57dd..f4dc9dd 100644 --- a/Craftimizer/Utils/MacroImport.cs +++ b/Craftimizer/Utils/MacroImport.cs @@ -1,7 +1,3 @@ -using Craftimizer.Plugin; -using Craftimizer.Simulator; -using Craftimizer.Simulator.Actions; -using Dalamud.Networking.Http; using System; using System.Collections.Generic; using System.Diagnostics; @@ -12,6 +8,10 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Craftimizer.Plugin; +using Craftimizer.Simulator; +using Craftimizer.Simulator.Actions; +using Dalamud.Networking.Http; using static Craftimizer.Utils.CommunityMacros; namespace Craftimizer.Utils; @@ -69,7 +69,10 @@ public static class MacroImport if (!Uri.TryCreate(url, UriKind.Absolute, out uri!)) return false; - if (!string.Equals(uri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) && !string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) + if ( + !string.Equals(uri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) + && !string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) + ) return false; if (!uri.IsDefaultPort) @@ -87,34 +90,46 @@ public static class MacroImport { "ffxivteamcraft.com" => RetrieveTeamcraftUrl(uri, token), "craftingway.app" => RetrieveCraftingwayUrl(uri, token), - _ => throw new UnreachableException("TryParseUrl should handle miscellaneous edge cases"), + _ => throw new UnreachableException( + "TryParseUrl should handle miscellaneous edge cases" + ), }; } private static async Task RetrieveTeamcraftUrl(Uri uri, CancellationToken token) { using var heCallback = new HappyEyeballsCallback(); - using var client = new HttpClient(new SocketsHttpHandler - { - AutomaticDecompression = DecompressionMethods.All, - ConnectCallback = heCallback.ConnectCallback, - }); + using var client = new HttpClient( + new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.All, + ConnectCallback = heCallback.ConnectCallback, + } + ); var path = uri.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped); if (!path.StartsWith("simulator/", StringComparison.Ordinal)) - throw new ArgumentException("Teamcraft macro url should start with /simulator", nameof(uri)); + throw new ArgumentException( + "Teamcraft macro url should start with /simulator", + nameof(uri) + ); path = path[10..]; var lastSlash = path.LastIndexOf('/'); if (lastSlash == -1) - throw new ArgumentException("Teamcraft macro url is not in the right format", nameof(uri)); + throw new ArgumentException( + "Teamcraft macro url is not in the right format", + nameof(uri) + ); var id = path[(lastSlash + 1)..]; - var resp = await client.GetFromJsonAsync( - $"https://firestore.googleapis.com/v1beta1/projects/ffxivteamcraft/databases/(default)/documents/rotations/{id}", - token). - ConfigureAwait(false); + var resp = await client + .GetFromJsonAsync( + $"https://firestore.googleapis.com/v1beta1/projects/ffxivteamcraft/databases/(default)/documents/rotations/{id}", + token + ) + .ConfigureAwait(false); if (resp is null) throw new Exception("Internal error; failed to retrieve macro"); if (resp.Error is { } error) @@ -122,31 +137,41 @@ public static class MacroImport return new(resp); } - private static async Task RetrieveCraftingwayUrl(Uri uri, CancellationToken token) + private static async Task RetrieveCraftingwayUrl( + Uri uri, + CancellationToken token + ) { using var heCallback = new HappyEyeballsCallback(); - using var client = new HttpClient(new SocketsHttpHandler - { - AutomaticDecompression = DecompressionMethods.All, - ConnectCallback = heCallback.ConnectCallback, - }); + using var client = new HttpClient( + new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.All, + ConnectCallback = heCallback.ConnectCallback, + } + ); // https://craftingway.app/rotation/variable-blueprint-KmrvS var path = uri.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped); if (!path.StartsWith("rotation/", StringComparison.Ordinal)) - throw new ArgumentException("Craftingway macro url should start with /rotation", nameof(uri)); + throw new ArgumentException( + "Craftingway macro url should start with /rotation", + nameof(uri) + ); path = path[9..]; var lastSlash = path.LastIndexOf('/'); if (lastSlash != -1) - throw new ArgumentException("Craftingway macro url is not in the right format", nameof(uri)); + throw new ArgumentException( + "Craftingway macro url is not in the right format", + nameof(uri) + ); var id = path; - var resp = await client.GetFromJsonAsync( - $"https://servingway.fly.dev/rotation/{id}", - token) + var resp = await client + .GetFromJsonAsync($"https://servingway.fly.dev/rotation/{id}", token) .ConfigureAwait(false); if (resp is null) throw new Exception("Internal error; failed to retrieve macro"); diff --git a/Craftimizer/Utils/RecipeData.cs b/Craftimizer/Utils/RecipeData.cs index 2ce10bd..994f8d9 100644 --- a/Craftimizer/Utils/RecipeData.cs +++ b/Craftimizer/Utils/RecipeData.cs @@ -1,9 +1,9 @@ -using Craftimizer.Plugin; -using Craftimizer.Simulator; -using Lumina.Excel.Sheets; using System; using System.Collections.Generic; using System.Linq; +using Craftimizer.Plugin; +using Craftimizer.Simulator; +using Lumina.Excel.Sheets; using ClassJob = Craftimizer.Simulator.ClassJob; namespace Craftimizer.Utils; @@ -28,16 +28,22 @@ public sealed record RecipeData { RecipeId = recipeId; - Recipe = LuminaSheets.RecipeSheet.GetRowOrDefault(recipeId) ?? - throw new ArgumentException($"Invalid recipe id {recipeId}", nameof(recipeId)); + Recipe = + LuminaSheets.RecipeSheet.GetRowOrDefault(recipeId) + ?? throw new ArgumentException($"Invalid recipe id {recipeId}", nameof(recipeId)); ClassJob = (ClassJob)Recipe.CraftType.RowId; var resolvedLevelTableRow = Recipe.RecipeLevelTable.RowId; if (Recipe.MaxAdjustableJobLevel.RowId != 0) { - AdjustedJobLevel = Math.Min(explicitlyAdjustedJobLevel ?? ClassJob.GetWKSSyncedLevel(), (ushort)Recipe.MaxAdjustableJobLevel.RowId); - resolvedLevelTableRow = LuminaSheets.GathererCrafterLvAdjustTableSheet.GetRow(AdjustedJobLevel.Value).RecipeLevel.RowId; + AdjustedJobLevel = Math.Min( + explicitlyAdjustedJobLevel ?? ClassJob.GetWKSSyncedLevel(), + (ushort)Recipe.MaxAdjustableJobLevel.RowId + ); + resolvedLevelTableRow = LuminaSheets + .GathererCrafterLvAdjustTableSheet.GetRow(AdjustedJobLevel.Value) + .RecipeLevel.RowId; } Table = LuminaSheets.RecipeLevelTableSheet.GetRow(resolvedLevelTableRow); @@ -46,8 +52,14 @@ public sealed record RecipeData IsExpert = Recipe.IsExpert, ClassJobLevel = Table.ClassJobLevel, ConditionsFlag = Table.ConditionsFlag, - MaxDurability = (Recipe.MaxAdjustableJobLevel.RowId != 0 ? 80 : Table.Durability) * Recipe.DurabilityFactor / 100, - MaxQuality = (Recipe.CanHq || Recipe.RequiredQuality > 0) ? (int)Table.Quality * Recipe.QualityFactor / 100 : 0, + MaxDurability = + (Recipe.MaxAdjustableJobLevel.RowId != 0 ? 80 : Table.Durability) + * Recipe.DurabilityFactor + / 100, + MaxQuality = + (Recipe.CanHq || Recipe.RequiredQuality > 0) + ? (int)Table.Quality * Recipe.QualityFactor / 100 + : 0, MaxProgress = Table.Difficulty * Recipe.DifficultyFactor / 100, QualityModifier = Table.QualityModifier, QualityDivider = Table.QualityDivider, @@ -64,23 +76,37 @@ public sealed record RecipeData { if (entry.ItemTradeIn.RowId == Recipe.ItemResult.RowId) { - thresholds = [entry.BaseCollectableRating, entry.MidCollectableRating, entry.HighCollectableRating]; + thresholds = + [ + entry.BaseCollectableRating, + entry.MidCollectableRating, + entry.HighCollectableRating, + ]; break; } } } - else if (Recipe.CollectableMetadata.GetValueOrDefaultSubrow() is { } row3) + else if ( + Recipe.CollectableMetadata.GetValueOrDefaultSubrow() is { } row3 + ) { foreach (var subrow in row3) { if (subrow.Item.RowId == Recipe.ItemResult.RowId) { - thresholds = [subrow.CollectabilityLow, subrow.CollectabilityMid, subrow.CollectabilityHigh]; + thresholds = + [ + subrow.CollectabilityLow, + subrow.CollectabilityMid, + subrow.CollectabilityHigh, + ]; break; } } } - else if (Recipe.CollectableMetadata.GetValueOrDefault() is { } row5) + else if ( + Recipe.CollectableMetadata.GetValueOrDefault() is { } row5 + ) { foreach (var item in row5.Item) { @@ -93,10 +119,19 @@ public sealed record RecipeData } else if (Recipe.CollectableMetadata.GetValueOrDefault() is { } row6) thresholds = [row6.CollectabilityLow, row6.CollectabilityMid, row6.CollectabilityHigh]; - else if (Recipe.CollectableMetadataKey == 7 && LuminaSheets.WKSMissionToDoEvalutionRefinSheet.TryGetRow(Recipe.CollectableMetadata.RowId, out var row7)) + else if ( + Recipe.CollectableMetadataKey == 7 + && LuminaSheets.WKSMissionToDoEvalutionRefinSheet.TryGetRow( + Recipe.CollectableMetadata.RowId, + out var row7 + ) + ) { thresholds = [row7.Unknown0, row7.Unknown1, row7.Unknown2]; - thresholds = [.. thresholds.Select(percentage => RecipeInfo.MaxQuality * percentage / 1000)]; + thresholds = + [ + .. thresholds.Select(percentage => RecipeInfo.MaxQuality * percentage / 1000), + ]; } if (thresholds != null) @@ -106,14 +141,17 @@ public sealed record RecipeData CollectableThresholds = t.ToArray(); } - Ingredients = Recipe.Ingredient.Zip(Recipe.AmountIngredient) + Ingredients = Recipe + .Ingredient.Zip(Recipe.AmountIngredient) .Take(6) .Where(i => i.First.IsValid) .Select(i => (i.First.Value, (int)i.Second)) .ToList(); - MaxStartingQuality = (int)Math.Floor(Recipe.MaterialQualityFactor * RecipeInfo.MaxQuality / 100f); + MaxStartingQuality = (int) + Math.Floor(Recipe.MaterialQualityFactor * RecipeInfo.MaxQuality / 100f); - TotalHqILvls = (int)Ingredients.Where(i => i.Item.CanBeHq).Sum(i => i.Item.LevelItem.RowId * i.Amount); + TotalHqILvls = (int) + Ingredients.Where(i => i.Item.CanBeHq).Sum(i => i.Item.LevelItem.RowId * i.Amount); } public int CalculateItemStartingQuality(int itemIdx, int amount) diff --git a/Craftimizer/Utils/SimulatedMacro.cs b/Craftimizer/Utils/SimulatedMacro.cs index edbb111..f6caaa1 100644 --- a/Craftimizer/Utils/SimulatedMacro.cs +++ b/Craftimizer/Utils/SimulatedMacro.cs @@ -1,10 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using DotNext.Collections.Generic; -using System; -using System.Collections.Generic; -using System.Linq; using Sim = Craftimizer.Simulator.Simulator; using SimNoRandom = Craftimizer.Simulator.SimulatorNoRandom; @@ -51,11 +51,11 @@ internal sealed class SimulatedMacro Average = (float)DataList.Average(); } - public ImGuiUtils.ViolinData? GetViolinData(float barMax, int resolution, double bandwidth) => - ViolinData ??= - Min != Max ? - new(DataList, 0, barMax, resolution, bandwidth) : - null; + public ImGuiUtils.ViolinData? GetViolinData( + float barMax, + int resolution, + double bandwidth + ) => ViolinData ??= Min != Max ? new(DataList, 0, barMax, resolution, bandwidth) : null; } public readonly Param Progress = new(); @@ -64,7 +64,12 @@ internal sealed class SimulatedMacro // Param is either collectability, quality, or hq%, depending on the recipe public readonly Param ParamScore = new(); - public Reliablity(in SimulationState startState, IEnumerable actions, int iterCount, RecipeData recipeData) + public Reliablity( + in SimulationState startState, + IEnumerable actions, + int iterCount, + RecipeData recipeData + ) { Func getParam; if (recipeData.IsCollectable) @@ -97,12 +102,18 @@ internal sealed class SimulatedMacro { public ActionType Action { get; } public bool IsEphemeral { get; } + // State *after* executing the action public ActionResponse Response { get; private set; } public SimulationState State { get; private set; } private Reliablity? Reliability { get; set; } - public Step(ActionType action, Sim sim, in SimulationState lastState, out SimulationState newState) + public Step( + ActionType action, + Sim sim, + in SimulationState lastState, + out SimulationState newState + ) { Action = action; newState = Recalculate(sim, lastState); @@ -122,9 +133,17 @@ internal sealed class SimulatedMacro return State; } - public Reliablity GetReliability(in SimulationState initialState, IEnumerable actionSet, RecipeData recipeData) => - Reliability ??= - new(initialState, actionSet, Service.Configuration.ReliabilitySimulationCount, recipeData); + public Reliablity GetReliability( + in SimulationState initialState, + IEnumerable actionSet, + RecipeData recipeData + ) => + Reliability ??= new( + initialState, + actionSet, + Service.Configuration.ReliabilitySimulationCount, + recipeData + ); }; private List Macro { get; set; } = []; @@ -162,9 +181,9 @@ internal sealed class SimulatedMacro } public Reliablity GetReliability(RecipeData recipeData, Index? idx = null) => - Macro.Count > 0 ? - Macro[idx ?? ^1].GetReliability(InitialState, Actions.ToArray(), recipeData) : - new(InitialState, Array.Empty(), 0, recipeData); + Macro.Count > 0 + ? Macro[idx ?? ^1].GetReliability(InitialState, Actions.ToArray(), recipeData) + : new(InitialState, Array.Empty(), 0, recipeData); private void TryRecalculateFrom(int index) { @@ -177,14 +196,11 @@ internal sealed class SimulatedMacro state = Macro[i].Recalculate(sim, state); } - public void RecalculateState() => - TryRecalculateFrom(0); + public void RecalculateState() => TryRecalculateFrom(0); - public void RemoveRange(int index, int count) => - Macro.RemoveRange(index, count); + public void RemoveRange(int index, int count) => Macro.RemoveRange(index, count); - public void Clear() => - Macro.Clear(); + public void Clear() => Macro.Clear(); public void Add(ActionType action) { @@ -247,7 +263,10 @@ internal sealed class SimulatedMacro QueuedEphemeralSteps.Clear(); foreach (var action in actions) { - if (maxSize is { } size && QueuedSteps.Count + QueuedEphemeralSteps.Count + Macro.Count >= size) + if ( + maxSize is { } size + && QueuedSteps.Count + QueuedEphemeralSteps.Count + Macro.Count >= size + ) return size; QueuedEphemeralSteps.Add(new(action, true)); diff --git a/Craftimizer/Utils/SqText.cs b/Craftimizer/Utils/SqText.cs index 3df27de..cbbda91 100644 --- a/Craftimizer/Utils/SqText.cs +++ b/Craftimizer/Utils/SqText.cs @@ -1,8 +1,8 @@ -using Dalamud.Game.Text; using System; using System.Collections.Frozen; using System.Collections.Generic; using System.Numerics; +using Dalamud.Game.Text; namespace Craftimizer.Utils; @@ -10,7 +10,10 @@ public static class SqText { public static SeIconChar LevelPrefix => SeIconChar.LevelEn; - public static readonly FrozenDictionary LevelNumReplacements = new Dictionary + public static readonly FrozenDictionary LevelNumReplacements = new Dictionary< + char, + SeIconChar + > { ['0'] = SeIconChar.Number0, ['1'] = SeIconChar.Number1, @@ -24,17 +27,18 @@ public static class SqText ['9'] = SeIconChar.Number9, }.ToFrozenDictionary(); - public static string ToLevelString(T value) where T : IBinaryInteger + public static string ToLevelString(T value) + where T : IBinaryInteger { var str = value.ToString() ?? throw new FormatException("Failed to format value"); - foreach(var (k, v) in LevelNumReplacements) + foreach (var (k, v) in LevelNumReplacements) str = str.Replace(k, v.ToIconChar()); return str; } public static bool TryParseLevelString(string str, out int result) { - foreach(var (k, v) in LevelNumReplacements) + foreach (var (k, v) in LevelNumReplacements) str = str.Replace(v.ToIconChar(), k); return int.TryParse(str, out result); } diff --git a/Craftimizer/Utils/SynthesisValues.cs b/Craftimizer/Utils/SynthesisValues.cs index 102d7d7..7cb9b49 100644 --- a/Craftimizer/Utils/SynthesisValues.cs +++ b/Craftimizer/Utils/SynthesisValues.cs @@ -1,9 +1,9 @@ +using System; using Craftimizer.Simulator; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; -using System; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.AtkValueType; namespace Craftimizer.Utils; @@ -12,7 +12,8 @@ internal sealed unsafe class SynthesisValues(AddonSynthesis* addon) { private AddonSynthesis* Addon { get; } = addon; - private ReadOnlySpan Values => new(Addon->AtkUnitBase.AtkValues, Addon->AtkUnitBase.AtkValuesCount); + private ReadOnlySpan Values => + new(Addon->AtkUnitBase.AtkValues, Addon->AtkUnitBase.AtkValuesCount); // Always 0? private uint IsInitializing => GetUInt(0); @@ -51,9 +52,7 @@ internal sealed unsafe class SynthesisValues(AddonSynthesis* addon) if (Addon == null) return null; var value = Values[i]; - return value.Type == ValueType.UInt ? - value.UInt : - null; + return value.Type == ValueType.UInt ? value.UInt : null; } private bool? TryGetBool(int i) @@ -61,9 +60,7 @@ internal sealed unsafe class SynthesisValues(AddonSynthesis* addon) if (Addon == null) return null; var value = Values[i]; - return value.Type == ValueType.Bool ? - value.Byte != 0 : - null; + return value.Type == ValueType.Bool ? value.Byte != 0 : null; } private SeString? TryGetString(int i) @@ -73,10 +70,10 @@ internal sealed unsafe class SynthesisValues(AddonSynthesis* addon) var value = Values[i]; return value.Type switch { - ValueType.ManagedString or - ValueType.String => - MemoryHelper.ReadSeStringNullTerminated((nint)value.String.Value), - _ => null + ValueType.ManagedString or ValueType.String => MemoryHelper.ReadSeStringNullTerminated( + (nint)value.String.Value + ), + _ => null, }; } diff --git a/Craftimizer/Windows/MacroClipboard.cs b/Craftimizer/Windows/MacroClipboard.cs index ea17af3..fd99d67 100644 --- a/Craftimizer/Windows/MacroClipboard.cs +++ b/Craftimizer/Windows/MacroClipboard.cs @@ -1,13 +1,13 @@ -using Craftimizer.Plugin; -using Dalamud.Interface; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Interface.Windowing; -using Dalamud.Bindings.ImGui; using System; using System.Collections.Generic; -using System.Numerics; using System.Linq; +using System.Numerics; +using Craftimizer.Plugin; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; using Dalamud.Interface.ImGuiNotification; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Interface.Windowing; namespace Craftimizer.Windows; @@ -17,7 +17,8 @@ public sealed class MacroClipboard : Window, IDisposable private List Macros { get; } - public MacroClipboard(IEnumerable macros) : base("Macro Clipboard", WindowFlags) + public MacroClipboard(IEnumerable macros) + : base("Macro Clipboard", WindowFlags) { Macros = [.. macros]; @@ -39,32 +40,49 @@ public sealed class MacroClipboard : Window, IDisposable private void DrawMacro(int idx, string macro) { using var id = ImRaii.PushId(idx); - using var panel = ImRaii2.GroupPanel(Macros.Count == 1 ? "Macro" : $"Macro {idx + 1}", -1, out var availWidth); + using var panel = ImRaii2.GroupPanel( + Macros.Count == 1 ? "Macro" : $"Macro {idx + 1}", + -1, + out var availWidth + ); var cursor = ImGui.GetCursorPos(); ImGuiUtils.AlignRight(ImGui.GetFrameHeight(), availWidth); var buttonCursor = ImGui.GetCursorPos(); ImGui.InvisibleButton("##copyInvButton", new(ImGui.GetFrameHeight())); - var buttonHovered = ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenOverlapped | ImGuiHoveredFlags.AllowWhenBlockedByActiveItem); + var buttonHovered = ImGui.IsItemHovered( + ImGuiHoveredFlags.AllowWhenOverlapped | ImGuiHoveredFlags.AllowWhenBlockedByActiveItem + ); var buttonActive = buttonHovered && ImGui.GetIO().MouseDown[(int)ImGuiMouseButton.Left]; - var buttonClicked = buttonHovered && ImGui.GetIO().MouseReleased[(int)ImGuiMouseButton.Left]; + var buttonClicked = + buttonHovered && ImGui.GetIO().MouseReleased[(int)ImGuiMouseButton.Left]; ImGui.SetCursorPos(buttonCursor); { - using var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(buttonActive ? ImGuiCol.ButtonActive : ImGuiCol.ButtonHovered), buttonHovered); + using var color = ImRaii.PushColor( + ImGuiCol.Button, + ImGui.GetColorU32(buttonActive ? ImGuiCol.ButtonActive : ImGuiCol.ButtonHovered), + buttonHovered + ); ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste); if (buttonClicked) { ImGui.SetClipboardText(macro); if (Service.Configuration.MacroCopy.ShowCopiedMessage) { - Plugin.Plugin.DisplayNotification(new() - { - Content = Macros.Count == 1 ? "Copied macro to clipboard." : $"Copied macro {idx + 1} to clipboard.", - MinimizedText = Macros.Count == 1 ? "Copied macro" : $"Copied macro {idx + 1}", - Title = "Macro Copied", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = + Macros.Count == 1 + ? "Copied macro to clipboard." + : $"Copied macro {idx + 1} to clipboard.", + MinimizedText = + Macros.Count == 1 ? "Copied macro" : $"Copied macro {idx + 1}", + Title = "Macro Copied", + Type = NotificationType.Success, + } + ); } } } @@ -77,7 +95,17 @@ public sealed class MacroClipboard : Window, IDisposable using var padding = ImRaii.PushStyle(ImGuiStyleVar.FramePadding, Vector2.Zero); using var bg = ImRaii.PushColor(ImGuiCol.FrameBg, Vector4.Zero); var lineCount = macro.Count(c => c == '\n') + 1; - ImGui.InputTextMultiline("", ref macro, macro.Length + 1, new(availWidth, ImGui.GetTextLineHeight() * Math.Max(15, lineCount) + ImGui.GetStyle().FramePadding.Y), ImGuiInputTextFlags.ReadOnly | ImGuiInputTextFlags.AutoSelectAll); + ImGui.InputTextMultiline( + "", + ref macro, + macro.Length + 1, + new( + availWidth, + ImGui.GetTextLineHeight() * Math.Max(15, lineCount) + + ImGui.GetStyle().FramePadding.Y + ), + ImGuiInputTextFlags.ReadOnly | ImGuiInputTextFlags.AutoSelectAll + ); } if (buttonHovered) diff --git a/Craftimizer/Windows/MacroEditor.cs b/Craftimizer/Windows/MacroEditor.cs index 784a8cb..cb1d278 100644 --- a/Craftimizer/Windows/MacroEditor.cs +++ b/Craftimizer/Windows/MacroEditor.cs @@ -1,7 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading; +using System.Threading.Tasks; using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; +using Craftimizer.Solver; using Craftimizer.Utils; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Statuses; using Dalamud.Game.Text; using Dalamud.Interface; @@ -12,19 +21,10 @@ using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; -using Dalamud.Bindings.ImGui; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading; -using System.Threading.Tasks; +using Dalamud.Utility; +using Recipe = Lumina.Excel.Sheets.Recipe; using Sim = Craftimizer.Simulator.Simulator; using SimNoRandom = Craftimizer.Simulator.SimulatorNoRandom; -using Recipe = Lumina.Excel.Sheets.Recipe; -using Dalamud.Utility; -using Craftimizer.Solver; namespace Craftimizer.Windows; @@ -73,6 +73,7 @@ public sealed class MacroEditor : Window, IDisposable } } } + public CrafterBuffs Buffs { get; set; } private List HQIngredientCounts { get; set; } @@ -111,7 +112,15 @@ public sealed class MacroEditor : Window, IDisposable private CancellationTokenSource? popupImportUrlTokenSource; private CommunityMacros.CommunityMacro? popupImportUrlMacro; - public MacroEditor(CharacterStats characterStats, RecipeData recipeData, CrafterBuffs buffs, IEnumerable? ingredientHqCounts, IEnumerable actions, Action>? setter) : base("Craftimizer Macro Editor", WindowFlags) + public MacroEditor( + CharacterStats characterStats, + RecipeData recipeData, + CrafterBuffs buffs, + IEnumerable? ingredientHqCounts, + IEnumerable actions, + Action>? setter + ) + : base("Craftimizer Macro Editor", WindowFlags) { CharacterStats = characterStats; RecipeData = recipeData; @@ -119,7 +128,10 @@ public sealed class MacroEditor : Window, IDisposable MacroSetter = setter; DefaultActions = [.. actions]; - HQIngredientCounts = [.. ingredientHqCounts ?? Enumerable.Repeat(0, RecipeData.Ingredients.Count)]; + HQIngredientCounts = + [ + .. ingredientHqCounts ?? Enumerable.Repeat(0, RecipeData.Ingredients.Count), + ]; RecalculateState(); foreach (var action in DefaultActions) @@ -136,7 +148,9 @@ public sealed class MacroEditor : Window, IDisposable MedicatedBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(49)!.Icon); InControlBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(356)!.Icon); EatFromTheHandBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(357)!.Icon); - AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis14)); + AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle( + new(GameFontFamilyAndSize.Axis14) + ); IsOpen = true; @@ -150,14 +164,15 @@ public sealed class MacroEditor : Window, IDisposable Icon = FontAwesomeIcon.Cog, IconOffset = new(2, 1), Click = _ => Service.Plugin.OpenSettingsTab("Macro Editor"), - ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings") + ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings"), }, - new() { + new() + { Icon = FontAwesomeIcon.Heart, IconOffset = new(2, 1), Click = _ => Util.OpenLink(Plugin.Plugin.SupportLink), - ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!") - } + ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!"), + }, ]; MinWindowHeight = float.PositiveInfinity; @@ -194,14 +209,19 @@ public sealed class MacroEditor : Window, IDisposable if (i == 0) height = widths[i].MinWidth; else - height = (int)float.Lerp( - widths[i - 1].MinWidth, widths[i].MinWidth, - (scale - widths[i - 1].Scale) / (widths[i].Scale - widths[i - 1].Scale) - ); + height = (int) + float.Lerp( + widths[i - 1].MinWidth, + widths[i].MinWidth, + (scale - widths[i - 1].Scale) / (widths[i].Scale - widths[i - 1].Scale) + ); break; } } - ImGui.SetNextWindowSizeConstraints(new Vector2(height, MinWindowHeight), new Vector2(float.PositiveInfinity)); + ImGui.SetNextWindowSizeConstraints( + new Vector2(height, MinWindowHeight), + new Vector2(float.PositiveInfinity) + ); } public override void OnClose() @@ -219,7 +239,13 @@ public sealed class MacroEditor : Window, IDisposable { var modifiedInput = false; - using (var table = ImRaii.Table("params", 2, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame)) + using ( + var table = ImRaii.Table( + "params", + 2, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ) + ) { if (table) { @@ -235,7 +261,13 @@ public sealed class MacroEditor : Window, IDisposable if (modifiedInput) RecalculateState(); - using (var table = ImRaii.Table("macroInfo", 2, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame)) + using ( + var table = ImRaii.Table( + "macroInfo", + 2, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ) + ) { if (table) { @@ -260,9 +292,7 @@ public sealed class MacroEditor : Window, IDisposable var textClassSize = AxisFont.CalcTextSize(textClassName); var imageSize = ImGui.GetFrameHeight(); - ImGuiUtils.AlignCentered( - imageSize + 5 + - textClassSize.X); + ImGuiUtils.AlignCentered(imageSize + 5 + textClassSize.X); ImGui.AlignTextToFramePadding(); var uv0 = new Vector2(6, 3); @@ -270,11 +300,22 @@ public sealed class MacroEditor : Window, IDisposable uv0 /= new Vector2(56); uv1 /= new Vector2(56); - ImGui.Image(Service.IconManager.GetIconCached(RecipeData.ClassJob.GetIconId()).Handle, new Vector2(imageSize), uv0, uv1); + ImGui.Image( + Service.IconManager.GetIconCached(RecipeData.ClassJob.GetIconId()).Handle, + new Vector2(imageSize), + uv0, + uv1 + ); ImGui.SameLine(0, 5); AxisFont.Text(textClassName); - using (var statsTable = ImRaii.Table("stats", 3, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame)) + using ( + var statsTable = ImRaii.Table( + "stats", + 3, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ) + ) { if (statsTable) { @@ -282,7 +323,10 @@ public sealed class MacroEditor : Window, IDisposable ImGui.TableSetupColumn("col2", ImGuiTableColumnFlags.WidthStretch, 3); ImGui.TableSetupColumn("col3", ImGuiTableColumnFlags.WidthStretch, 2); - var inputWidth = ImGui.CalcTextSize(SqText.ToLevelString(9999)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; + var inputWidth = + ImGui.CalcTextSize(SqText.ToLevelString(9999)).X + + ImGui.GetStyle().FramePadding.X * 2 + + 5; void DrawStat(string name, int value, Action setter) { @@ -292,27 +336,51 @@ public sealed class MacroEditor : Window, IDisposable ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); var text = value.ToString(); - if (ImGui.InputText($"##{name}", ref text, 8, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal)) + if ( + ImGui.InputText( + $"##{name}", + ref text, + 8, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal + ) + ) { setter( - int.TryParse(text, out var newLevel) - ? Math.Clamp(newLevel, 0, 9999) - : 0); + int.TryParse(text, out var newLevel) ? Math.Clamp(newLevel, 0, 9999) : 0 + ); } } ImGui.TableNextColumn(); - DrawStat("Craftsmanship", CharacterStats.Craftsmanship, v => CharacterStats = CharacterStats with { Craftsmanship = v }); + DrawStat( + "Craftsmanship", + CharacterStats.Craftsmanship, + v => CharacterStats = CharacterStats with { Craftsmanship = v } + ); ImGui.TableNextColumn(); - DrawStat("Control", CharacterStats.Control, v => CharacterStats = CharacterStats with { Control = v }); + DrawStat( + "Control", + CharacterStats.Control, + v => CharacterStats = CharacterStats with { Control = v } + ); ImGui.TableNextColumn(); - DrawStat("CP", CharacterStats.CP, v => CharacterStats = CharacterStats with { CP = v }); + DrawStat( + "CP", + CharacterStats.CP, + v => CharacterStats = CharacterStats with { CP = v } + ); } } - using (var paramTable = ImRaii.Table("params", 3, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame)) + using ( + var paramTable = ImRaii.Table( + "params", + 3, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ) + ) { if (paramTable) { @@ -327,10 +395,7 @@ public sealed class MacroEditor : Window, IDisposable var level = CharacterStats.Level; if (DrawLevelEntry(ref level)) { - CharacterStats = CharacterStats with - { - Level = level - }; + CharacterStats = CharacterStats with { Level = level }; } } @@ -339,18 +404,35 @@ public sealed class MacroEditor : Window, IDisposable var imageButtonSize = imageSize - imageButtonPadding * 2; { var splendorousLevel = 90; - if (CharacterStats.HasSplendorousBuff && splendorousLevel > CharacterStats.Level) + if ( + CharacterStats.HasSplendorousBuff + && splendorousLevel > CharacterStats.Level + ) CharacterStats = CharacterStats with { HasSplendorousBuff = false }; using (var d = ImRaii.Disabled(splendorousLevel > CharacterStats.Level)) { var v = CharacterStats.HasSplendorousBuff; var tint = v ? Vector4.One : disabledTint; - if (ImGui.ImageButton(SplendorousBadge.Handle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + if ( + ImGui.ImageButton( + SplendorousBadge.Handle, + new Vector2(imageButtonSize), + default, + Vector2.One, + imageButtonPadding, + default, + tint + ) + ) CharacterStats = CharacterStats with { HasSplendorousBuff = !v }; } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGuiUtils.Tooltip(CharacterStats.HasSplendorousBuff ? $"Splendorous Tool" : "No Splendorous Tool"); + ImGuiUtils.Tooltip( + CharacterStats.HasSplendorousBuff + ? $"Splendorous Tool" + : "No Splendorous Tool" + ); } ImGui.SameLine(0, 5); bool? newIsSpecialist = null; @@ -363,8 +445,19 @@ public sealed class MacroEditor : Window, IDisposable using (var d = ImRaii.Disabled(specialistLevel > CharacterStats.Level)) { - var tint = new Vector4(0.99f, 0.97f, 0.62f, 1f) * (v ? Vector4.One : disabledTint); - if (ImGui.ImageButton(SpecialistBadge.Handle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + var tint = + new Vector4(0.99f, 0.97f, 0.62f, 1f) * (v ? Vector4.One : disabledTint); + if ( + ImGui.ImageButton( + SpecialistBadge.Handle, + new Vector2(imageButtonSize), + default, + Vector2.One, + imageButtonPadding, + default, + tint + ) + ) { v = !v; newIsSpecialist = v; @@ -375,21 +468,42 @@ public sealed class MacroEditor : Window, IDisposable } ImGui.SameLine(0, 5); { - var manipLevel = ActionType.Manipulation.GetActionRow(RecipeData.ClassJob).Action!.Value.ClassJobLevel; + var manipLevel = ActionType + .Manipulation.GetActionRow(RecipeData.ClassJob) + .Action!.Value.ClassJobLevel; using (var d = ImRaii.Disabled(manipLevel > CharacterStats.Level)) { - var v = CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level; - var tint = (v || manipLevel > CharacterStats.Level) ? disabledTint : Vector4.One; - if (ImGui.ImageButton((v ? ManipulationBadge : NoManipulationBadge).Handle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + var v = + CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level; + var tint = + (v || manipLevel > CharacterStats.Level) ? disabledTint : Vector4.One; + if ( + ImGui.ImageButton( + (v ? ManipulationBadge : NoManipulationBadge).Handle, + new Vector2(imageButtonSize), + default, + Vector2.One, + imageButtonPadding, + default, + tint + ) + ) CharacterStats = CharacterStats with { CanUseManipulation = !v }; } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGuiUtils.Tooltip(CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level ? $"Can Use Manipulation" : "Cannot Use Manipulation"); + ImGuiUtils.Tooltip( + CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level + ? $"Can Use Manipulation" + : "Cannot Use Manipulation" + ); } ImGui.TableNextColumn(); - var buffBadgeSize = new Vector2(imageSize * (WellFedBadge.AspectRatio ?? 1), imageSize); + var buffBadgeSize = new Vector2( + imageSize * (WellFedBadge.AspectRatio ?? 1), + imageSize + ); (uint ItemId, bool HQ)? newFoodBuff = null; ImGui.Image(WellFedBadge.Handle, buffBadgeSize); @@ -472,9 +586,14 @@ public sealed class MacroEditor : Window, IDisposable ImGui.SameLine(0, 5); { ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - using var combo = ImRaii.Combo("##fcCraftsmanship", FormatFCBuff(fcBuffName, Buffs.FC.Craftsmanship)); + using var combo = ImRaii.Combo( + "##fcCraftsmanship", + FormatFCBuff(fcBuffName, Buffs.FC.Craftsmanship) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip(FormatFCBuffDescription(fcBuffName, fcStatName, Buffs.FC.Craftsmanship)); + ImGuiUtils.Tooltip( + FormatFCBuffDescription(fcBuffName, fcStatName, Buffs.FC.Craftsmanship) + ); if (combo) { if (ImGui.Selectable("None", Buffs.FC.Craftsmanship == 0)) @@ -482,10 +601,17 @@ public sealed class MacroEditor : Window, IDisposable for (var i = 1; i <= 3; ++i) { - if (ImGui.Selectable(FormatFCBuff(fcBuffName, i), Buffs.FC.Craftsmanship == i)) + if ( + ImGui.Selectable( + FormatFCBuff(fcBuffName, i), + Buffs.FC.Craftsmanship == i + ) + ) newFCCraftsmanshipBuff = i; if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip(FormatFCBuffDescription(fcBuffName, fcStatName, i)); + ImGuiUtils.Tooltip( + FormatFCBuffDescription(fcBuffName, fcStatName, i) + ); } } } @@ -499,9 +625,14 @@ public sealed class MacroEditor : Window, IDisposable ImGui.SameLine(0, 5); { ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - using var combo = ImRaii.Combo("##fcControl", FormatFCBuff(fcBuffName, Buffs.FC.Control)); + using var combo = ImRaii.Combo( + "##fcControl", + FormatFCBuff(fcBuffName, Buffs.FC.Control) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip(FormatFCBuffDescription(fcBuffName, fcStatName, Buffs.FC.Control)); + ImGuiUtils.Tooltip( + FormatFCBuffDescription(fcBuffName, fcStatName, Buffs.FC.Control) + ); if (combo) { if (ImGui.Selectable("None", Buffs.FC.Control == 0)) @@ -509,15 +640,25 @@ public sealed class MacroEditor : Window, IDisposable for (var i = 1; i <= 3; ++i) { - if (ImGui.Selectable(FormatFCBuff(fcBuffName, i), Buffs.FC.Control == i)) + if ( + ImGui.Selectable(FormatFCBuff(fcBuffName, i), Buffs.FC.Control == i) + ) newFCControlBuff = i; if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip(FormatFCBuffDescription(fcBuffName, fcStatName, i)); + ImGuiUtils.Tooltip( + FormatFCBuffDescription(fcBuffName, fcStatName, i) + ); } } } - if (newIsSpecialist.HasValue || newFoodBuff.HasValue || newMedicineBuff.HasValue || newFCCraftsmanshipBuff.HasValue || newFCControlBuff.HasValue) + if ( + newIsSpecialist.HasValue + || newFoodBuff.HasValue + || newMedicineBuff.HasValue + || newFCCraftsmanshipBuff.HasValue + || newFCControlBuff.HasValue + ) { var baseStat = GetBaseStats(CharacterStats); @@ -525,10 +666,18 @@ public sealed class MacroEditor : Window, IDisposable { Food = newFoodBuff ?? Buffs.Food, Medicine = newMedicineBuff ?? Buffs.Medicine, - FC = (newFCCraftsmanshipBuff ?? Buffs.FC.Craftsmanship, newFCControlBuff ?? Buffs.FC.Control) + FC = ( + newFCCraftsmanshipBuff ?? Buffs.FC.Craftsmanship, + newFCControlBuff ?? Buffs.FC.Control + ), }; - var newStats = CharacterStats with { Craftsmanship = baseStat.Craftsmanship, Control = baseStat.Control, CP = baseStat.CP }; + var newStats = CharacterStats with + { + Craftsmanship = baseStat.Craftsmanship, + Control = baseStat.Control, + CP = baseStat.CP, + }; if (newIsSpecialist is { } isSpecialist) { if (isSpecialist != CharacterStats.IsSpecialist) @@ -548,7 +697,7 @@ public sealed class MacroEditor : Window, IDisposable IsSpecialist = isSpecialist, Craftsmanship = newStats.Craftsmanship + craftsmanship, Control = newStats.Control + control, - CP = newStats.CP + cp + CP = newStats.CP + cp, }; } } @@ -558,7 +707,7 @@ public sealed class MacroEditor : Window, IDisposable { Craftsmanship = newStats.Craftsmanship + bonus.Craftsmanship, Control = newStats.Control + bonus.Control, - CP = newStats.CP + bonus.CP + CP = newStats.CP + bonus.CP, }; } } @@ -572,7 +721,9 @@ public sealed class MacroEditor : Window, IDisposable if (input.ItemId == 0) return "None"; - var name = LuminaSheets.ItemSheet.GetRowOrDefault(input.ItemId)?.Name.ToString() ?? $"Unknown ({input.ItemId})"; + var name = + LuminaSheets.ItemSheet.GetRowOrDefault(input.ItemId)?.Name.ToString() + ?? $"Unknown ({input.ItemId})"; return input.IsHQ ? $"{name} (HQ)" : name; } @@ -628,7 +779,13 @@ public sealed class MacroEditor : Window, IDisposable var food = FoodStatus.TryGetFood(Buffs.Food.ItemId); var medicine = FoodStatus.TryGetFood(Buffs.Medicine.ItemId); - static void GetBaseStat(ref int val, bool isHq, FoodStatus.FoodStat? food, out float a, out int b) + static void GetBaseStat( + ref int val, + bool isHq, + FoodStatus.FoodStat? food, + out float a, + out int b + ) { a = 1; b = 0; @@ -644,15 +801,33 @@ public sealed class MacroEditor : Window, IDisposable } } - static int GetBaseStat2(int val, bool foodHq, FoodStatus.FoodStat? food, bool medicineHq, FoodStatus.FoodStat? medicine) + static int GetBaseStat2( + int val, + bool foodHq, + FoodStatus.FoodStat? food, + bool medicineHq, + FoodStatus.FoodStat? medicine + ) { GetBaseStat(ref val, foodHq, food, out var a, out var b); GetBaseStat(ref val, medicineHq, medicine, out var c, out var d); return CalculateBaseStat(val, a, b, c, d); } - craftsmanship = GetBaseStat2(craftsmanship, Buffs.Food.IsHQ, food?.Craftsmanship, Buffs.Medicine.IsHQ, medicine?.Craftsmanship); - control = GetBaseStat2(control, Buffs.Food.IsHQ, food?.Control, Buffs.Medicine.IsHQ, medicine?.Control); + craftsmanship = GetBaseStat2( + craftsmanship, + Buffs.Food.IsHQ, + food?.Craftsmanship, + Buffs.Medicine.IsHQ, + medicine?.Craftsmanship + ); + control = GetBaseStat2( + control, + Buffs.Food.IsHQ, + food?.Control, + Buffs.Medicine.IsHQ, + medicine?.Control + ); cp = GetBaseStat2(cp, Buffs.Food.IsHQ, food?.CP, Buffs.Medicine.IsHQ, medicine?.CP); return (craftsmanship, control, cp); @@ -660,13 +835,19 @@ public sealed class MacroEditor : Window, IDisposable private (int Craftsmanship, int Control, int CP) CalculateConsumableBonus(CharacterStats stats) { - int craftsmanship = 0, control = 0, cp = 0; + int craftsmanship = 0, + control = 0, + cp = 0; static int CalculateStatBonus(int val, bool isHq, FoodStatus.FoodStat? food) { if (food is { } stat) { if (stat.IsRelative) - return (int)Math.Min((isHq ? stat.ValueHQ : stat.Value) / 100f * val, isHq ? stat.MaxHQ : stat.Max); + return (int) + Math.Min( + (isHq ? stat.ValueHQ : stat.Value) / 100f * val, + isHq ? stat.MaxHQ : stat.Max + ); else return isHq ? stat.ValueHQ : stat.Value; } @@ -674,12 +855,20 @@ public sealed class MacroEditor : Window, IDisposable } var food = FoodStatus.TryGetFood(Buffs.Food.ItemId); - craftsmanship += CalculateStatBonus(stats.Craftsmanship, Buffs.Food.IsHQ, food?.Craftsmanship); + craftsmanship += CalculateStatBonus( + stats.Craftsmanship, + Buffs.Food.IsHQ, + food?.Craftsmanship + ); control += CalculateStatBonus(stats.Control, Buffs.Food.IsHQ, food?.Control); cp += CalculateStatBonus(stats.CP, Buffs.Food.IsHQ, food?.CP); var medicine = FoodStatus.TryGetFood(Buffs.Medicine.ItemId); - craftsmanship += CalculateStatBonus(stats.Craftsmanship, Buffs.Medicine.IsHQ, medicine?.Craftsmanship); + craftsmanship += CalculateStatBonus( + stats.Craftsmanship, + Buffs.Medicine.IsHQ, + medicine?.Craftsmanship + ); control += CalculateStatBonus(stats.Control, Buffs.Medicine.IsHQ, medicine?.Control); cp += CalculateStatBonus(stats.CP, Buffs.Medicine.IsHQ, medicine?.CP); @@ -717,8 +906,7 @@ public sealed class MacroEditor : Window, IDisposable { public readonly Recipe Recipe = recipe; - public bool Equals(RecipeWrapper other) => - Recipe.RowId == other.Recipe.RowId; + public bool Equals(RecipeWrapper other) => Recipe.RowId == other.Recipe.RowId; public override bool Equals(object? obj) { @@ -731,7 +919,12 @@ public sealed class MacroEditor : Window, IDisposable } } - private readonly List searchableRecipes = [.. LuminaSheets.RecipeSheet.Where(r => r.RecipeLevelTable.RowId != 0 && r.ItemResult.RowId != 0).Select(r => new RecipeWrapper(r))]; + private readonly List searchableRecipes = + [ + .. LuminaSheets + .RecipeSheet.Where(r => r.RecipeLevelTable.RowId != 0 && r.ItemResult.RowId != 0) + .Select(r => new RecipeWrapper(r)), + ]; private bool DrawRecipeParams() { @@ -753,7 +946,9 @@ public sealed class MacroEditor : Window, IDisposable } else { - textLevel = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(RecipeData.RecipeInfo.ClassJobLevel); + textLevel = + SqText.LevelPrefix.ToIconChar() + + SqText.ToLevelString(RecipeData.RecipeInfo.ClassJobLevel); textLevelSize = ImGui.CalcTextSize(textLevel).X; } @@ -766,14 +961,18 @@ public sealed class MacroEditor : Window, IDisposable var badgeOffset = (imageSize - badgeSize.Y) / 2; var rightSideWidth = - 5 + textLevelSize + - (textStarsSize != Vector2.Zero ? textStarsSize.X + 3 : 0) + - (isAdjustable ? imageSize + 3 : 0) + - (isCollectable ? badgeSize.X + 3 : 0) + - (isExpert ? badgeSize.X + 3 : 0); + 5 + + textLevelSize + + (textStarsSize != Vector2.Zero ? textStarsSize.X + 3 : 0) + + (isAdjustable ? imageSize + 3 : 0) + + (isCollectable ? badgeSize.X + 3 : 0) + + (isExpert ? badgeSize.X + 3 : 0); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value.Icon).Handle, new Vector2(imageSize)); + ImGui.Image( + Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value.Icon).Handle, + new Vector2(imageSize) + ); ImGui.SameLine(0, 5); @@ -782,40 +981,54 @@ public sealed class MacroEditor : Window, IDisposable var recipe = new RecipeWrapper(RecipeData.Recipe); using var lockedFontHandle = AxisFont.Available ? AxisFont.Lock() : null; var fontHandle = lockedFontHandle?.ImFont ?? ImGui.GetFont(); - if (ImGuiUtils.SearchableCombo( - "combo", - ref recipe, - searchableRecipes, - fontHandle, - ImGui.GetContentRegionAvail().X - rightSideWidth, - r => r.Recipe.ItemResult.Value.Name.ToString(), - r => r.Recipe.RowId.ToString(), - r => - { - ImGui.TextUnformatted($"{r.Recipe.ItemResult.Value.Name}"); + if ( + ImGuiUtils.SearchableCombo( + "combo", + ref recipe, + searchableRecipes, + fontHandle, + ImGui.GetContentRegionAvail().X - rightSideWidth, + r => r.Recipe.ItemResult.Value.Name.ToString(), + r => r.Recipe.RowId.ToString(), + r => + { + ImGui.TextUnformatted($"{r.Recipe.ItemResult.Value.Name}"); - var classJob = (ClassJob)r.Recipe.CraftType.RowId; - var textLevel = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(r.Recipe.RecipeLevelTable.Value!.ClassJobLevel); - var textLevelSize = ImGui.CalcTextSize(textLevel); - ImGui.SameLine(); + var classJob = (ClassJob)r.Recipe.CraftType.RowId; + var textLevel = + SqText.LevelPrefix.ToIconChar() + + SqText.ToLevelString(r.Recipe.RecipeLevelTable.Value!.ClassJobLevel); + var textLevelSize = ImGui.CalcTextSize(textLevel); + ImGui.SameLine(); - var imageSize = fontHandle.FontSize; - ImGuiUtils.AlignRight( - imageSize + 5 + - textLevelSize.X, - ImGui.GetContentRegionAvail().X); + var imageSize = fontHandle.FontSize; + ImGuiUtils.AlignRight( + imageSize + 5 + textLevelSize.X, + ImGui.GetContentRegionAvail().X + ); - var uv0 = new Vector2(6, 3); - var uv1 = uv0 + new Vector2(44); - uv0 /= new Vector2(56); - uv1 /= new Vector2(56); + var uv0 = new Vector2(6, 3); + var uv1 = uv0 + new Vector2(44); + uv0 /= new Vector2(56); + uv1 /= new Vector2(56); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().FramePadding.Y / 2); - ImGui.Image(Service.IconManager.GetIconCached(classJob.GetIconId()).Handle, new Vector2(imageSize), uv0, uv1); - ImGui.SameLine(0, 5); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (fontHandle.FontSize - textLevelSize.Y) / 2); - ImGui.TextUnformatted(textLevel); - })) + ImGui.SetCursorPosY( + ImGui.GetCursorPosY() + ImGui.GetStyle().FramePadding.Y / 2 + ); + ImGui.Image( + Service.IconManager.GetIconCached(classJob.GetIconId()).Handle, + new Vector2(imageSize), + uv0, + uv1 + ); + ImGui.SameLine(0, 5); + ImGui.SetCursorPosY( + ImGui.GetCursorPosY() + (fontHandle.FontSize - textLevelSize.Y) / 2 + ); + ImGui.TextUnformatted(textLevel); + } + ) + ) { newRecipe = (ushort)recipe.Recipe.RowId; } @@ -897,7 +1110,13 @@ public sealed class MacroEditor : Window, IDisposable } } - using (var table = ImRaii.Table("ingredientTable", 4, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame)) + using ( + var table = ImRaii.Table( + "ingredientTable", + 4, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ) + ) { if (table) { @@ -975,21 +1194,32 @@ public sealed class MacroEditor : Window, IDisposable { var perItem = RecipeData.CalculateItemStartingQuality(idx, 1); var total = RecipeData.CalculateItemStartingQuality(idx, hqCount); - ImGuiUtils.Tooltip($"{ingredient.Item.Name} {SeIconChar.HighQuality.ToIconString()}\n+{perItem} Quality/Item{(total > 0 ? $"\n+{total} Quality" : "")}"); + ImGuiUtils.Tooltip( + $"{ingredient.Item.Name} {SeIconChar.HighQuality.ToIconString()}\n+{perItem} Quality/Item{(total > 0 ? $"\n+{total} Quality" : "")}" + ); } else if (ingredient.Amount != 0) ImGuiUtils.Tooltip($"{ingredient.Item.Name}"); } ImGui.SameLine(0, 5); - ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - (5 + ImGui.CalcTextSize("/").X + 5 + ImGui.CalcTextSize($"99").X)); + ImGui.SetNextItemWidth( + ImGui.GetContentRegionAvail().X + - (5 + ImGui.CalcTextSize("/").X + 5 + ImGui.CalcTextSize($"99").X) + ); using var d2 = ImRaii.Disabled(!canHq); if (canHq) { var text = hqCount.ToString(); - if (ImGui.InputText($"##ingredient{idx}", ref text, 8, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal)) + if ( + ImGui.InputText( + $"##ingredient{idx}", + ref text, + 8, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal + ) + ) { - HQIngredientCounts[idx] = - int.TryParse(text, out var newCount) + HQIngredientCounts[idx] = int.TryParse(text, out var newCount) ? Math.Clamp(newCount, 0, ingredient.Amount) : 0; } @@ -997,7 +1227,12 @@ public sealed class MacroEditor : Window, IDisposable else { var text = ingredient.Amount.ToString(); - ImGui.InputText($"##ingredient{idx}", ref text, 8, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal); + ImGui.InputText( + $"##ingredient{idx}", + ref text, + 8, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal + ); } ImGui.SameLine(0, 5); ImGui.AlignTextToFramePadding(); @@ -1008,9 +1243,13 @@ public sealed class MacroEditor : Window, IDisposable } private const int MAX_LEVEL = 100; + private static float GetLevelEntryWidth() { - var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; + var levelTextWidth = + ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + + ImGui.GetStyle().FramePadding.X * 2 + + 5; return ImGui.CalcTextSize(SqText.LevelPrefix.ToIconString()).X + 5 + levelTextWidth; } @@ -1029,19 +1268,28 @@ public sealed class MacroEditor : Window, IDisposable return 0; } - var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; + var levelTextWidth = + ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + + ImGui.GetStyle().FramePadding.X * 2 + + 5; ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(SqText.LevelPrefix.ToIconString()); ImGui.SameLine(0, 3); ImGui.SetNextItemWidth(levelTextWidth); var levelText = SqText.ToLevelString(level); - var textChanged = ImGui.InputText("##levelText", ref levelText, 12, ImGuiInputTextFlags.CallbackCharFilter | ImGuiInputTextFlags.AutoSelectAll, LevelInputCallback); + var textChanged = ImGui.InputText( + "##levelText", + ref levelText, + 12, + ImGuiInputTextFlags.CallbackCharFilter | ImGuiInputTextFlags.AutoSelectAll, + LevelInputCallback + ); if (textChanged) { var newLevel = SqText.TryParseLevelString(levelText, out var lv) - ? Math.Clamp(lv, 1, MAX_LEVEL) - : 1; + ? Math.Clamp(lv, 1, MAX_LEVEL) + : 1; if (newLevel != level) { level = newLevel; @@ -1061,7 +1309,10 @@ public sealed class MacroEditor : Window, IDisposable using var _color = ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero); using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero); using var _color2 = ImRaii.PushColor(ImGuiCol.ButtonActive, Vector4.Zero); - using var _alpha = ImRaii.PushStyle(ImGuiStyleVar.DisabledAlpha, ImGui.GetStyle().DisabledAlpha * .5f); + using var _alpha = ImRaii.PushStyle( + ImGuiStyleVar.DisabledAlpha, + ImGui.GetStyle().DisabledAlpha * .5f + ); foreach (var category in Enum.GetValues()) { if (category == ActionCategory.Combo) @@ -1080,31 +1331,70 @@ public sealed class MacroEditor : Window, IDisposable { var actionBase = actions[i].Base(); var canUse = actionBase.CanUse(sim); - if (ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(imageSize), default, Vector2.One, 0, default, !canUse ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One) && !SolverRunning) + if ( + ImGui.ImageButton( + actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(imageSize), + default, + Vector2.One, + 0, + default, + !canUse ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One + ) && !SolverRunning + ) AddStep(actions[i]); - if (!canUse && - (CharacterStats.Level < actionBase.Level || - (actions[i] == ActionType.Manipulation && !CharacterStats.CanUseManipulation) || - (actions[i] is ActionType.HeartAndSoul or ActionType.CarefulObservation or ActionType.QuickInnovation && !CharacterStats.IsSpecialist) + if ( + !canUse + && ( + CharacterStats.Level < actionBase.Level + || ( + actions[i] == ActionType.Manipulation + && !CharacterStats.CanUseManipulation + ) + || ( + actions[i] + is ActionType.HeartAndSoul + or ActionType.CarefulObservation + or ActionType.QuickInnovation + && !CharacterStats.IsSpecialist + ) ) - ) + ) { - Vector2 v1 = ImGui.GetItemRectMin(), v2 = ImGui.GetItemRectMax(); + Vector2 v1 = ImGui.GetItemRectMin(), + v2 = ImGui.GetItemRectMax(); ImGui.PushClipRect(v1, v2, true); (v1.X, v2.X) = (v2.X, v1.X); - ImGui.GetWindowDrawList().AddLine(v1, v2, ImGui.GetColorU32(new Vector4(1, 0, 0, ImGui.GetStyle().DisabledAlpha / 2)), 5 * ImGuiHelpers.GlobalScale); + ImGui + .GetWindowDrawList() + .AddLine( + v1, + v2, + ImGui.GetColorU32( + new Vector4(1, 0, 0, ImGui.GetStyle().DisabledAlpha / 2) + ), + 5 * ImGuiHelpers.GlobalScale + ); ImGui.PopClipRect(); } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGuiUtils.Tooltip($"{actions[i].GetName(RecipeData!.ClassJob)}\n{actionBase.GetTooltip(sim, true)}"); + ImGuiUtils.Tooltip( + $"{actions[i].GetName(RecipeData!.ClassJob)}\n{actionBase.GetTooltip(sim, true)}" + ); - using var _padding = ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, Vector2.Zero); + using var _padding = ImRaii.PushStyle( + ImGuiStyleVar.WindowPadding, + Vector2.Zero + ); using (var _source = ImRaii.DragDropSource()) { if (_source) { ImGuiExtras.SetDragDropPayload("macroActionInsert", actions[i]); - ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(imageSize)); + ImGui.ImageButton( + actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(imageSize) + ); } } } @@ -1113,7 +1403,10 @@ public sealed class MacroEditor : Window, IDisposable } } - var minY = ImGui.GetCursorPosY() + ImGui.GetStyle().WindowPadding.Y - ImGui.GetStyle().CellPadding.Y; + var minY = + ImGui.GetCursorPosY() + + ImGui.GetStyle().WindowPadding.Y + - ImGui.GetStyle().CellPadding.Y; if (MinWindowHeight != minY) MinWindowHeight = minY; } @@ -1137,27 +1430,43 @@ public sealed class MacroEditor : Window, IDisposable using (var g = ImRaii.Group()) { var availSize = totalSize - (spacing + ImGui.GetFrameHeight()); - var size = ImGui.GetFrameHeight() + spacing + ImGui.CalcTextSize(condition.Name()).X; + var size = + ImGui.GetFrameHeight() + + spacing + + ImGui.CalcTextSize(condition.Name()).X; ImGuiUtils.AlignCentered(size, availSize); - ImGui.GetWindowDrawList().AddCircleFilled( - ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetFrameHeight() / 2), - ImGui.GetFrameHeight() / 2, - ImGui.ColorConvertFloat4ToU32(new Vector4(.35f, .35f, .35f, 0) + condition.GetColor(DateTime.UtcNow.TimeOfDay))); + ImGui + .GetWindowDrawList() + .AddCircleFilled( + ImGui.GetCursorScreenPos() + + new Vector2(ImGui.GetFrameHeight() / 2), + ImGui.GetFrameHeight() / 2, + ImGui.ColorConvertFloat4ToU32( + new Vector4(.35f, .35f, .35f, 0) + + condition.GetColor(DateTime.UtcNow.TimeOfDay) + ) + ); ImGui.Dummy(new(ImGui.GetFrameHeight())); ImGui.SameLine(0, spacing); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(condition.Name()); } if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip(condition.Description(CharacterStats.HasSplendorousBuff)); + ImGuiUtils.Tooltip( + condition.Description(CharacterStats.HasSplendorousBuff) + ); ImGui.SetCursorPos(pos); ImGuiUtils.AlignRight(ImGui.GetFrameHeight(), totalSize); using (var disabled = ImRaii.Disabled(SolverRunning)) { - using var tint = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !Service.Configuration.ConditionRandomness); + using var tint = ImRaii.PushColor( + ImGuiCol.Text, + ImGui.GetColorU32(ImGuiCol.TextDisabled), + !Service.Configuration.ConditionRandomness + ); if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Dice)) { Service.Configuration.ConditionRandomness ^= true; @@ -1167,32 +1476,83 @@ public sealed class MacroEditor : Window, IDisposable } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGuiUtils.TooltipWrapped($"Condition Randomness{(!Service.Configuration.ConditionRandomness ? " (Disabled)" : string.Empty)}\n" + - "Allows the condition to fluctuate randomly like a real craft. " + - "Turns off when generating a macro."); + ImGuiUtils.TooltipWrapped( + $"Condition Randomness{(!Service.Configuration.ConditionRandomness ? " (Disabled)" : string.Empty)}\n" + + "Allows the condition to fluctuate randomly like a real craft. " + + "Turns off when generating a macro." + ); } var datas = new List(3) { - new("Durability", Colors.Durability, State.Durability, RecipeData.RecipeInfo.MaxDurability), - new("Condition", DrawCondition) + new( + "Durability", + Colors.Durability, + State.Durability, + RecipeData.RecipeInfo.MaxDurability + ), + new("Condition", DrawCondition), }; if (RecipeData.IsCollectable) - datas.Add(new("Collectability", Colors.Collectability, Reliability.ParamScore, State.Collectability, State.MaxCollectability, RecipeData.CollectableThresholds, $"{State.Collectability}", $"{State.MaxCollectability:0}")); + datas.Add( + new( + "Collectability", + Colors.Collectability, + Reliability.ParamScore, + State.Collectability, + State.MaxCollectability, + RecipeData.CollectableThresholds, + $"{State.Collectability}", + $"{State.MaxCollectability:0}" + ) + ); else if (RecipeData.Recipe.RequiredQuality > 0) { - var qualityPercent = (float)State.Quality / RecipeData.Recipe.RequiredQuality * 100; - datas.Add(new("Quality %", Colors.HQ, Reliability.ParamScore, qualityPercent, 100, null, $"{qualityPercent:0}%")); + var qualityPercent = + (float)State.Quality / RecipeData.Recipe.RequiredQuality * 100; + datas.Add( + new( + "Quality %", + Colors.HQ, + Reliability.ParamScore, + qualityPercent, + 100, + null, + $"{qualityPercent:0}%" + ) + ); } else if (RecipeData.RecipeInfo.MaxQuality > 0) - datas.Add(new("HQ %", Colors.HQ, Reliability.ParamScore, State.HQPercent, 100, null, $"{State.HQPercent}%")); + datas.Add( + new( + "HQ %", + Colors.HQ, + Reliability.ParamScore, + State.HQPercent, + 100, + null, + $"{State.HQPercent}%" + ) + ); DynamicBars.Draw(datas); ImGui.TableNextColumn(); datas = [ - new("Progress", Colors.Progress, Reliability.Progress, State.Progress, RecipeData.RecipeInfo.MaxProgress), - new("Quality", Colors.Quality, Reliability.Quality, State.Quality, RecipeData.RecipeInfo.MaxQuality), - new("CP", Colors.CP, State.CP, CharacterStats.CP) + new( + "Progress", + Colors.Progress, + Reliability.Progress, + State.Progress, + RecipeData.RecipeInfo.MaxProgress + ), + new( + "Quality", + Colors.Quality, + Reliability.Quality, + State.Quality, + RecipeData.RecipeInfo.MaxQuality + ), + new("CP", Colors.CP, State.CP, CharacterStats.CP), ]; if (RecipeData.RecipeInfo.MaxQuality <= 0) datas.RemoveAt(1); @@ -1209,7 +1569,11 @@ public sealed class MacroEditor : Window, IDisposable var buffIconHeight = ImGui.GetFrameHeight() * 1.75f; var buffDurationShift = buffIconHeight * .2f; - var buffHeight = buffIconHeight + ImGui.GetStyle().ItemSpacing.Y + ImGui.GetTextLineHeight() - buffDurationShift; + var buffHeight = + buffIconHeight + + ImGui.GetStyle().ItemSpacing.Y + + ImGui.GetTextLineHeight() + - buffDurationShift; var infoHeight = 3 * ImGui.GetTextLineHeightWithSpacing(); @@ -1233,7 +1597,10 @@ public sealed class MacroEditor : Window, IDisposable using (var group = ImRaii.Group()) { var icon = effect.GetIcon(effects.GetStrength(effect)); - var size = new Vector2(buffIconHeight * (icon.AspectRatio ?? 1), buffIconHeight); + var size = new Vector2( + buffIconHeight * (icon.AspectRatio ?? 1), + buffIconHeight + ); ImGui.Image(icon.Handle, size); if (!effect.IsIndefinite()) @@ -1261,7 +1628,8 @@ public sealed class MacroEditor : Window, IDisposable var waitTimeOptimal = waitTime - actions.Length; var delineationCount = actions.Count(SolverConfig.SpecialistActions.Contains); - var height = (delineationCount == 0 ? 2 : 3) * ImGui.GetTextLineHeightWithSpacing(); + var height = + (delineationCount == 0 ? 2 : 3) * ImGui.GetTextLineHeightWithSpacing(); ImGui.Dummy(new(0, panelHeight)); ImGui.SameLine(0, 0); @@ -1269,12 +1637,16 @@ public sealed class MacroEditor : Window, IDisposable using (ImRaii.Group()) { ImGui.SetCursorPosY(ImGui.GetCursorPos().Y + (panelHeight - height) / 2f); - ImGuiUtils.TextCentered($"{actions.Length} Step{(actions.Length != 1 ? "s" : string.Empty)}"); + ImGuiUtils.TextCentered( + $"{actions.Length} Step{(actions.Length != 1 ? "s" : string.Empty)}" + ); ImGuiUtils.TextCentered($"{waitTime} sec"); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Optimal Time: {waitTimeOptimal:0.#} sec"); if (delineationCount != 0) - ImGuiUtils.TextCentered($"{delineationCount} Delineation{(delineationCount != 1 ? "s" : string.Empty)}"); + ImGuiUtils.TextCentered( + $"{delineationCount} Delineation{(delineationCount != 1 ? "s" : string.Empty)}" + ); } } } @@ -1292,53 +1664,105 @@ public sealed class MacroEditor : Window, IDisposable ImGui.SameLine(0, 0); var macroActionsHeight = ImGui.GetFrameHeightWithSpacing() * (1 + (SolverRunning ? 1 : 0)); - var childHeight = ImGui.GetContentRegionAvail().Y - ImGui.GetStyle().ItemSpacing.Y * 2 - ImGui.GetStyle().CellPadding.Y - macroActionsHeight - ImGui.GetStyle().ItemSpacing.Y * 2; + var childHeight = + ImGui.GetContentRegionAvail().Y + - ImGui.GetStyle().ItemSpacing.Y * 2 + - ImGui.GetStyle().CellPadding.Y + - macroActionsHeight + - ImGui.GetStyle().ItemSpacing.Y * 2; using (var child = ImRaii.Child("##macroActions", new(availSpace, childHeight))) { - var itemsPerRow = (int)Math.Max(1, MathF.Floor((ImGui.GetContentRegionAvail().X + spacing) / (imageSize + spacing))); + var itemsPerRow = (int) + Math.Max( + 1, + MathF.Floor((ImGui.GetContentRegionAvail().X + spacing) / (imageSize + spacing)) + ); using var _color = ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero); using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero); using var _color2 = ImRaii.PushColor(ImGuiCol.ButtonActive, Vector4.Zero); - using var _alpha = ImRaii.PushStyle(ImGuiStyleVar.DisabledAlpha, ImGui.GetStyle().DisabledAlpha * .5f); + using var _alpha = ImRaii.PushStyle( + ImGuiStyleVar.DisabledAlpha, + ImGui.GetStyle().DisabledAlpha * .5f + ); for (var i = 0; i < Macro.Count; i++) { if (i % itemsPerRow != 0) ImGui.SameLine(0, spacing); - var (action, response, state) = (Macro[i].Action, Macro[i].Response, Macro[i].State); + var (action, response, state) = ( + Macro[i].Action, + Macro[i].Response, + Macro[i].State + ); var actionBase = action.Base(); var failedAction = response != ActionResponse.UsedAction; using var id = ImRaii.PushId(i); - if (ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).Handle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One) && !SolverRunning) + if ( + ImGui.ImageButton( + action.GetIcon(RecipeData!.ClassJob).Handle, + new(imageSize), + default, + Vector2.One, + 0, + default, + failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One + ) && !SolverRunning + ) RemoveStep(i); - if (response is ActionResponse.ActionNotUnlocked || - ( - failedAction && - (CharacterStats.Level < actionBase.Level || - (action == ActionType.Manipulation && !CharacterStats.CanUseManipulation) || - (action is ActionType.HeartAndSoul or ActionType.CarefulObservation && !CharacterStats.IsSpecialist) + if ( + response is ActionResponse.ActionNotUnlocked + || ( + failedAction + && ( + CharacterStats.Level < actionBase.Level + || ( + action == ActionType.Manipulation + && !CharacterStats.CanUseManipulation + ) + || ( + action is ActionType.HeartAndSoul or ActionType.CarefulObservation + && !CharacterStats.IsSpecialist + ) ) ) ) { - Vector2 v1 = ImGui.GetItemRectMin(), v2 = ImGui.GetItemRectMax(); + Vector2 v1 = ImGui.GetItemRectMin(), + v2 = ImGui.GetItemRectMax(); ImGui.PushClipRect(v1, v2, true); (v1.X, v2.X) = (v2.X, v1.X); - ImGui.GetWindowDrawList().AddLine(v1, v2, ImGui.GetColorU32(new Vector4(1, 0, 0, ImGui.GetStyle().DisabledAlpha / 2)), 5 * ImGuiHelpers.GlobalScale); + ImGui + .GetWindowDrawList() + .AddLine( + v1, + v2, + ImGui.GetColorU32( + new Vector4(1, 0, 0, ImGui.GetStyle().DisabledAlpha / 2) + ), + 5 * ImGuiHelpers.GlobalScale + ); ImGui.PopClipRect(); } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGuiUtils.Tooltip($"{action.GetName(RecipeData!.ClassJob)}\n{actionBase.GetTooltip(CreateSim(lastState), true)}"); + ImGuiUtils.Tooltip( + $"{action.GetName(RecipeData!.ClassJob)}\n{actionBase.GetTooltip(CreateSim(lastState), true)}" + ); if (!SolverRunning) { - using var _padding = ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, Vector2.Zero); + using var _padding = ImRaii.PushStyle( + ImGuiStyleVar.WindowPadding, + Vector2.Zero + ); using (var _source = ImRaii.DragDropSource()) { if (_source) { ImGuiExtras.SetDragDropPayload("macroAction", i); - ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).Handle, new(imageSize)); + ImGui.ImageButton( + action.GetIcon(RecipeData!.ClassJob).Handle, + new(imageSize) + ); } } using (var _target = ImRaii.DragDropTarget()) @@ -1347,7 +1771,12 @@ public sealed class MacroEditor : Window, IDisposable { if (ImGuiExtras.AcceptDragDropPayload("macroAction", out int j)) Macro.Move(j, i); - else if (ImGuiExtras.AcceptDragDropPayload("macroActionInsert", out ActionType newAction)) + else if ( + ImGuiExtras.AcceptDragDropPayload( + "macroActionInsert", + out ActionType newAction + ) + ) Macro.Insert(i, newAction); } } @@ -1358,7 +1787,9 @@ public sealed class MacroEditor : Window, IDisposable var pos = ImGui.GetCursorScreenPos(); ImGui.Dummy(default); - ImGui.GetWindowDrawList().AddLine(pos, pos + new Vector2(availSpace, 0), ImGui.GetColorU32(ImGuiCol.Border)); + ImGui + .GetWindowDrawList() + .AddLine(pos, pos + new Vector2(availSpace, 0), ImGui.GetColorU32(ImGuiCol.Border)); ImGui.Dummy(default); if (SolverRunning && SolverObject is { } solver) DynamicBars.DrawProgressBar(solver, availSpace); @@ -1406,7 +1837,12 @@ public sealed class MacroEditor : Window, IDisposable } else { - if (ImGui.Button(SolverStartStepCount.HasValue ? "Regenerate" : "Generate", new(halfWidth, height))) + if ( + ImGui.Button( + SolverStartStepCount.HasValue ? "Regenerate" : "Generate", + new(halfWidth, height) + ) + ) CalculateBestMacro(); } ImGui.SameLine(); @@ -1456,7 +1892,13 @@ public sealed class MacroEditor : Window, IDisposable { ImGui.OpenPopup($"##saveAsPopup"); popupSaveAsMacroName = string.Empty; - ImGui.SetNextWindowPos(ImGui.GetMousePos() - new Vector2(ImGui.CalcItemWidth() * .25f, ImGui.GetFrameHeight() + ImGui.GetStyle().WindowPadding.Y * 2)); + ImGui.SetNextWindowPos( + ImGui.GetMousePos() + - new Vector2( + ImGui.CalcItemWidth() * .25f, + ImGui.GetFrameHeight() + ImGui.GetStyle().WindowPadding.Y * 2 + ) + ); } private void DrawSaveAsPopup() @@ -1467,11 +1909,23 @@ public sealed class MacroEditor : Window, IDisposable if (ImGui.IsWindowAppearing()) ImGui.SetKeyboardFocusHere(); ImGui.SetNextItemWidth(ImGui.CalcItemWidth()); - if (ImGui.InputTextWithHint($"##setName", "Name", ref popupSaveAsMacroName, 100, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue)) + if ( + ImGui.InputTextWithHint( + $"##setName", + "Name", + ref popupSaveAsMacroName, + 100, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue + ) + ) { if (!string.IsNullOrWhiteSpace(popupSaveAsMacroName)) { - var newMacro = new Macro() { Name = popupSaveAsMacroName, Actions = Macro.Actions.ToArray() }; + var newMacro = new Macro() + { + Name = popupSaveAsMacroName, + Actions = Macro.Actions.ToArray(), + }; Service.Configuration.AddMacro(newMacro); MacroSetter = actions => { @@ -1496,15 +1950,25 @@ public sealed class MacroEditor : Window, IDisposable private void DrawImportPopup() { - const string ExampleMacro = "/mlock\n/ac \"Muscle Memory\" \n/ac Manipulation \n/ac Veneration \n/ac \"Waste Not II\" \n/ac Groundwork \n/ac Innovation \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Great Strides\" \n/ac \"Byregot's Blessing\" \n/ac \"Careful Synthesis\" "; - const string ExampleUrl = "https://ffxivteamcraft.com/simulator/39630/35499/9XOZDZKhbVXJUIPXjM63"; + const string ExampleMacro = + "/mlock\n/ac \"Muscle Memory\" \n/ac Manipulation \n/ac Veneration \n/ac \"Waste Not II\" \n/ac Groundwork \n/ac Innovation \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Preparatory Touch\" \n/ac \"Great Strides\" \n/ac \"Byregot's Blessing\" \n/ac \"Careful Synthesis\" "; + const string ExampleUrl = + "https://ffxivteamcraft.com/simulator/39630/35499/9XOZDZKhbVXJUIPXjM63"; - ImGui.SetNextWindowPos(ImGui.GetMainViewport().GetCenter(), ImGuiCond.Always, new Vector2(0.5f)); + ImGui.SetNextWindowPos( + ImGui.GetMainViewport().GetCenter(), + ImGuiCond.Always, + new Vector2(0.5f) + ); ImGui.SetNextWindowSizeConstraints(new(400, 0), new(float.PositiveInfinity)); - using var popup = ImRaii.Popup($"##importPopup", ImGuiWindowFlags.Modal | ImGuiWindowFlags.NoMove); + using var popup = ImRaii.Popup( + $"##importPopup", + ImGuiWindowFlags.Modal | ImGuiWindowFlags.NoMove + ); if (popup) { - bool submittedText, submittedUrl; + bool submittedText, + submittedUrl; using (var panel = ImRaii2.GroupPanel("##text", -1, out var availWidth)) { @@ -1512,7 +1976,17 @@ public sealed class MacroEditor : Window, IDisposable ImGuiUtils.TextCentered("Paste your macro here"); { using var font = ImRaii.PushFont(UiBuilder.MonoFont); - ImGuiUtils.InputTextMultilineWithHint("", ExampleMacro, ref popupImportText, 2048, new(availWidth, ImGui.GetTextLineHeight() * 15 + ImGui.GetStyle().FramePadding.Y), ImGuiInputTextFlags.AutoSelectAll); + ImGuiUtils.InputTextMultilineWithHint( + "", + ExampleMacro, + ref popupImportText, + 2048, + new( + availWidth, + ImGui.GetTextLineHeight() * 15 + ImGui.GetStyle().FramePadding.Y + ), + ImGuiInputTextFlags.AutoSelectAll + ); } using (var _disabled = ImRaii.Disabled(popupImportUrlTokenSource != null)) submittedText = ImGui.Button("Import", new(availWidth, 0)); @@ -1528,7 +2002,10 @@ public sealed class MacroEditor : Window, IDisposable using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey)) { using var font = ImRaii.PushFont(UiBuilder.IconFont); - ImGuiUtils.TextRight(FontAwesomeIcon.InfoCircle.ToIconString(), ImGui.GetContentRegionAvail().X - availOffset); + ImGuiUtils.TextRight( + FontAwesomeIcon.InfoCircle.ToIconString(), + ImGui.GetContentRegionAvail().X - availOffset + ); } if (ImGui.IsItemHovered()) { @@ -1539,7 +2016,13 @@ public sealed class MacroEditor : Window, IDisposable ImGui.TextUnformatted("More suggestions are appreciated!"); } ImGui.SetNextItemWidth(availWidth); - submittedUrl = ImGui.InputTextWithHint("", ExampleUrl, ref popupImportUrl, 2048, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue); + submittedUrl = ImGui.InputTextWithHint( + "", + ExampleUrl, + ref popupImportUrl, + 2048, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue + ); using (var _disabled = ImRaii.Disabled(popupImportUrlTokenSource != null)) submittedUrl = ImGui.Button("Import", new(availWidth, 0)) || submittedUrl; } @@ -1553,7 +2036,9 @@ public sealed class MacroEditor : Window, IDisposable ImGui.Dummy(default); } - if (ImGuiUtils.ButtonCentered("Nevermind", new(ImGui.GetContentRegionAvail().X / 2f, 0))) + if ( + ImGuiUtils.ButtonCentered("Nevermind", new(ImGui.GetContentRegionAvail().X / 2f, 0)) + ) { popupImportUrlTokenSource?.Cancel(); ImGui.CloseCurrentPopup(); @@ -1570,18 +2055,22 @@ public sealed class MacroEditor : Window, IDisposable foreach (var action in parsedActions) AddStep(action); - Plugin.Plugin.DisplayNotification(new() - { - Content = $"Imported macro with {parsedActions.Count} step{(parsedActions.Count != 1 ? "s" : "")}", - MinimizedText = $"Imported {parsedActions.Count} step macro", - Title = "Macro Imported", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = + $"Imported macro with {parsedActions.Count} step{(parsedActions.Count != 1 ? "s" : "")}", + MinimizedText = $"Imported {parsedActions.Count} step macro", + Title = "Macro Imported", + Type = NotificationType.Success, + } + ); popupImportUrlTokenSource?.Cancel(); ImGui.CloseCurrentPopup(); } else - popupImportError = "Could not find any actions to import. Is it a valid macro?"; + popupImportError = + "Could not find any actions to import. Is it a valid macro?"; } if (submittedUrl) { @@ -1598,40 +2087,54 @@ public sealed class MacroEditor : Window, IDisposable if (token == popupImportUrlTokenSource.Token) popupImportUrlTokenSource = null; }); - _ = task.ContinueWith(t => - { - if (token.IsCancellationRequested) - return; + _ = task.ContinueWith( + t => + { + if (token.IsCancellationRequested) + return; - try - { - t.Exception!.Flatten().Handle(ex => ex is TaskCanceledException or OperationCanceledException); - } - catch (AggregateException e) - { - if (e.InnerExceptions.Count == 1) - popupImportError = e.InnerExceptions[0].Message; - else - popupImportError = e.Message; - Log.Error(e, "Retrieving macro failed"); - } - }, TaskContinuationOptions.OnlyOnFaulted); - _ = task.ContinueWith(t => popupImportUrlMacro = t.Result, TaskContinuationOptions.OnlyOnRanToCompletion); + try + { + t.Exception!.Flatten() + .Handle(ex => + ex + is TaskCanceledException + or OperationCanceledException + ); + } + catch (AggregateException e) + { + if (e.InnerExceptions.Count == 1) + popupImportError = e.InnerExceptions[0].Message; + else + popupImportError = e.Message; + Log.Error(e, "Retrieving macro failed"); + } + }, + TaskContinuationOptions.OnlyOnFaulted + ); + _ = task.ContinueWith( + t => popupImportUrlMacro = t.Result, + TaskContinuationOptions.OnlyOnRanToCompletion + ); } else - popupImportError = "The url is not in the right format for any supported sites."; + popupImportError = + "The url is not in the right format for any supported sites."; } if (popupImportUrlMacro is { Name: var name, Actions: var actions }) { Macro.Clear(); foreach (var action in actions) AddStep(action); - Plugin.Plugin.DisplayNotification(new() - { - Content = $"Imported macro \"{name}\"", - Title = "Macro Imported", - Type = NotificationType.Success - }); + Plugin.Plugin.DisplayNotification( + new() + { + Content = $"Imported macro \"{name}\"", + Title = "Macro Imported", + Type = NotificationType.Success, + } + ); popupImportUrlTokenSource?.Cancel(); ImGui.CloseCurrentPopup(); @@ -1666,7 +2169,11 @@ public sealed class MacroEditor : Window, IDisposable SolverTask.Start(); } - private int CalculateBestMacroTask(SimulationState state, CancellationToken token, bool hasDelineations) + private int CalculateBestMacroTask( + SimulationState state, + CancellationToken token, + bool hasDelineations + ) { var config = Service.Configuration.EditorSolverConfig; var canUseDelineations = !Service.Configuration.CheckDelineations || hasDelineations; @@ -1704,11 +2211,15 @@ public sealed class MacroEditor : Window, IDisposable private void RecalculateState() { - Macro.InitialState = new SimulationState(new(CharacterStats, RecipeData.RecipeInfo, StartingQuality)); + Macro.InitialState = new SimulationState( + new(CharacterStats, RecipeData.RecipeInfo, StartingQuality) + ); } private static Sim CreateSim(in SimulationState state) => - Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state }; + Service.Configuration.ConditionRandomness + ? new Sim() { State = state } + : new SimNoRandom() { State = state }; private void AddStep(ActionType action) { diff --git a/Craftimizer/Windows/MacroList.cs b/Craftimizer/Windows/MacroList.cs index 809471d..05dd10e 100644 --- a/Craftimizer/Windows/MacroList.cs +++ b/Craftimizer/Windows/MacroList.cs @@ -1,18 +1,18 @@ -using Craftimizer.Plugin; -using Craftimizer.Utils; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Interface; -using Dalamud.Interface.Windowing; -using Dalamud.Bindings.ImGui; using System; -using Craftimizer.Simulator; -using Craftimizer.Simulator.Actions; using System.Collections.Generic; using System.Linq; using System.Numerics; -using Sim = Craftimizer.Simulator.SimulatorNoRandom; +using Craftimizer.Plugin; +using Craftimizer.Simulator; +using Craftimizer.Simulator.Actions; +using Craftimizer.Utils; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Interface.Windowing; using Dalamud.Utility; +using Sim = Craftimizer.Simulator.SimulatorNoRandom; namespace Craftimizer.Windows; @@ -26,7 +26,8 @@ public sealed class MacroList : Window, IDisposable private static IReadOnlyList Macros => Service.Configuration.Macros; private Dictionary MacroStateCache { get; } = []; - public MacroList() : base("Craftimizer Macro List", WindowFlags, false) + public MacroList() + : base("Craftimizer Macro List", WindowFlags, false) { RefreshSearch(); @@ -36,7 +37,11 @@ public sealed class MacroList : Window, IDisposable CollapsedCondition = ImGuiCond.Appearing; Collapsed = false; - SizeConstraints = new() { MinimumSize = new(465, 520), MaximumSize = new(float.PositiveInfinity) }; + SizeConstraints = new() + { + MinimumSize = new(465, 520), + MaximumSize = new(float.PositiveInfinity), + }; TitleBarButtons = [ @@ -45,14 +50,15 @@ public sealed class MacroList : Window, IDisposable Icon = FontAwesomeIcon.Cog, IconOffset = new(2, 1), Click = _ => Service.Plugin.OpenSettingsTab("General"), - ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings") + ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings"), }, - new() { + new() + { Icon = FontAwesomeIcon.Heart, IconOffset = new(2, 1), Click = _ => Util.OpenLink(Plugin.Plugin.SupportLink), - ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!") - } + ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!"), + }, ]; Service.WindowSystem.AddWindow(this); @@ -90,7 +96,9 @@ public sealed class MacroList : Window, IDisposable ImGui.InvisibleButton($"###macroButton{i}", ImGui.GetItemRectSize()); if (isUnsorted) { - using (var _source = ImRaii.DragDropSource(ImGuiDragDropFlags.SourceNoDisableHover)) + using ( + var _source = ImRaii.DragDropSource(ImGuiDragDropFlags.SourceNoDisableHover) + ) { if (_source) { @@ -115,7 +123,10 @@ public sealed class MacroList : Window, IDisposable var text2 = "the Macro Editor here or from the Crafting Log."; var text3 = "Open Crafting Log"; var text4 = "Open Macro Editor"; - var buttonRowWidth = ImGui.CalcTextSize(text3).X + ImGui.CalcTextSize(text4).X + ImGui.GetStyle().ItemSpacing.X * 5; + var buttonRowWidth = + ImGui.CalcTextSize(text3).X + + ImGui.CalcTextSize(text4).X + + ImGui.GetStyle().ItemSpacing.X * 5; var size = new Vector2( Math.Max( Math.Max(ImGui.CalcTextSize(text1).X, ImGui.CalcTextSize(text2).X), @@ -139,6 +150,7 @@ public sealed class MacroList : Window, IDisposable private string searchText = string.Empty; private List sortedMacros = null!; private bool isUnsorted = true; + private void DrawSearchBar() { ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); @@ -157,12 +169,20 @@ public sealed class MacroList : Window, IDisposable var stateNullable = GetMacroState(macro); - using var panel = ImRaii2.GroupPanel(macro.Name, width - ImGui.GetStyle().ItemSpacing.X * 2, out var availWidth); + using var panel = ImRaii2.GroupPanel( + macro.Name, + width - ImGui.GetStyle().ItemSpacing.X * 2, + out var availWidth + ); var stepsAvailWidthOffset = width - availWidth; var spacing = ImGui.GetStyle().ItemSpacing.Y; var miniRowHeight = (windowHeight - spacing) / 2f; - using var table = ImRaii.Table("table", stateNullable.HasValue ? 3 : 2, ImGuiTableFlags.BordersInnerV); + using var table = ImRaii.Table( + "table", + stateNullable.HasValue ? 3 : 2, + ImGuiTableFlags.BordersInnerV + ); if (table) { if (stateNullable.HasValue) @@ -177,27 +197,36 @@ public sealed class MacroList : Window, IDisposable if (Service.Configuration.ShowOptimalMacroStat) { var progressHeight = windowHeight; - if (state.Progress >= state.Input.Recipe.MaxProgress && state.Input.Recipe.MaxQuality > 0) + if ( + state.Progress >= state.Input.Recipe.MaxProgress + && state.Input.Recipe.MaxQuality > 0 + ) { ImGuiUtils.ArcProgress( - (float)state.Quality / state.Input.Recipe.MaxQuality, - progressHeight / 2f, - .5f, - ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Quality)); + (float)state.Quality / state.Input.Recipe.MaxQuality, + progressHeight / 2f, + .5f, + ImGui.GetColorU32(ImGuiCol.TableBorderLight), + ImGui.GetColorU32(Colors.Quality) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Quality: {state.Quality} / {state.Input.Recipe.MaxQuality}"); + ImGuiUtils.Tooltip( + $"Quality: {state.Quality} / {state.Input.Recipe.MaxQuality}" + ); } else { ImGuiUtils.ArcProgress( - (float)state.Progress / state.Input.Recipe.MaxProgress, - progressHeight / 2f, - .5f, - ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Progress)); + (float)state.Progress / state.Input.Recipe.MaxProgress, + progressHeight / 2f, + .5f, + ImGui.GetColorU32(ImGuiCol.TableBorderLight), + ImGui.GetColorU32(Colors.Progress) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Progress: {state.Progress} / {state.Input.Recipe.MaxProgress}"); + ImGuiUtils.Tooltip( + $"Progress: {state.Progress} / {state.Input.Recipe.MaxProgress}" + ); } } else @@ -207,9 +236,12 @@ public sealed class MacroList : Window, IDisposable miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Progress)); + ImGui.GetColorU32(Colors.Progress) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Progress: {state.Progress} / {state.Input.Recipe.MaxProgress}"); + ImGuiUtils.Tooltip( + $"Progress: {state.Progress} / {state.Input.Recipe.MaxProgress}" + ); ImGui.SameLine(0, spacing); ImGuiUtils.ArcProgress( @@ -217,17 +249,24 @@ public sealed class MacroList : Window, IDisposable miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Quality)); + ImGui.GetColorU32(Colors.Quality) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Quality: {state.Quality} / {state.Input.Recipe.MaxQuality}"); + ImGuiUtils.Tooltip( + $"Quality: {state.Quality} / {state.Input.Recipe.MaxQuality}" + ); - ImGuiUtils.ArcProgress((float)state.Durability / state.Input.Recipe.MaxDurability, + ImGuiUtils.ArcProgress( + (float)state.Durability / state.Input.Recipe.MaxDurability, miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Durability)); + ImGui.GetColorU32(Colors.Durability) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Remaining Durability: {state.Durability} / {state.Input.Recipe.MaxDurability}"); + ImGuiUtils.Tooltip( + $"Remaining Durability: {state.Durability} / {state.Input.Recipe.MaxDurability}" + ); ImGui.SameLine(0, spacing); ImGuiUtils.ArcProgress( @@ -235,7 +274,8 @@ public sealed class MacroList : Window, IDisposable miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.CP)); + ImGui.GetColorU32(Colors.CP) + ); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Remaining CP: {state.CP} / {state.Input.Stats.CP}"); } @@ -270,7 +310,11 @@ public sealed class MacroList : Window, IDisposable ImGui.TableNextColumn(); { - var itemsPerRow = (int)MathF.Floor((ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset + spacing * 2) / (miniRowHeight + spacing)); + var itemsPerRow = (int) + MathF.Floor( + (ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset + spacing * 2) + / (miniRowHeight + spacing) + ); var itemCount = macro.Actions.Count; for (var i = 0; i < itemsPerRow * 2; i++) { @@ -281,7 +325,10 @@ public sealed class MacroList : Window, IDisposable var shouldShowMore = i + 1 == itemsPerRow * 2 && i + 1 < itemCount; if (!shouldShowMore) { - ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(miniRowHeight)); + ImGui.Image( + macro.Actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(miniRowHeight) + ); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip(macro.Actions[i].GetName(RecipeData!.ClassJob)); } @@ -289,12 +336,36 @@ public sealed class MacroList : Window, IDisposable { var amtMore = itemCount - itemsPerRow * 2; var pos = ImGui.GetCursorPos(); - ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); + ImGui.Image( + macro.Actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(miniRowHeight), + default, + Vector2.One, + new(1, 1, 1, .5f) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"{macro.Actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more"); + ImGuiUtils.Tooltip( + $"{macro.Actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more" + ); ImGui.SetCursorPos(pos); - ImGui.GetWindowDrawList().AddRectFilled(ImGui.GetCursorScreenPos(), ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), ImGui.GetColorU32(ImGuiCol.FrameBg), miniRowHeight / 8f); - ImGui.GetWindowDrawList().AddTextClippedEx(ImGui.GetCursorScreenPos(), ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), $"+{amtMore}", null, new(.5f), null); + ImGui + .GetWindowDrawList() + .AddRectFilled( + ImGui.GetCursorScreenPos(), + ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), + ImGui.GetColorU32(ImGuiCol.FrameBg), + miniRowHeight / 8f + ); + ImGui + .GetWindowDrawList() + .AddTextClippedEx( + ImGui.GetCursorScreenPos(), + ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), + $"+{amtMore}", + null, + new(.5f), + null + ); } } else @@ -306,12 +377,19 @@ public sealed class MacroList : Window, IDisposable private string popupMacroName = string.Empty; private Macro? popupMacro; + private void ShowRenamePopup(Macro macro) { ImGui.OpenPopup($"##renamePopup-{macro.GetHashCode()}"); popupMacro = macro; popupMacroName = macro.Name; - ImGui.SetNextWindowPos(ImGui.GetMousePos() - new Vector2(ImGui.CalcItemWidth() * .25f, ImGui.GetFrameHeight() + ImGui.GetStyle().WindowPadding.Y * 2)); + ImGui.SetNextWindowPos( + ImGui.GetMousePos() + - new Vector2( + ImGui.CalcItemWidth() * .25f, + ImGui.GetFrameHeight() + ImGui.GetStyle().WindowPadding.Y * 2 + ) + ); } private void DrawRenamePopup(Macro macro) @@ -322,7 +400,15 @@ public sealed class MacroList : Window, IDisposable if (ImGui.IsWindowAppearing()) ImGui.SetKeyboardFocusHere(); ImGui.SetNextItemWidth(ImGui.CalcItemWidth()); - if (ImGui.InputTextWithHint($"##setName", "Name", ref popupMacroName, 100, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue)) + if ( + ImGui.InputTextWithHint( + $"##setName", + "Name", + ref popupMacroName, + 100, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.EnterReturnsTrue + ) + ) { if (!string.IsNullOrWhiteSpace(popupMacroName)) { @@ -349,7 +435,9 @@ public sealed class MacroList : Window, IDisposable } isUnsorted = false; var matcher = new FuzzyMatcher(searchText.ToLowerInvariant(), MatchMode.FuzzyParts); - var query = Macros.AsParallel().Select(i => (Item: i, Score: matcher.Matches(i.Name.ToLowerInvariant()))) + var query = Macros + .AsParallel() + .Select(i => (Item: i, Score: matcher.Matches(i.Name.ToLowerInvariant()))) .Where(t => t.Score > 0) .OrderByDescending(t => t.Score) .Select(t => t.Item); @@ -359,7 +447,22 @@ public sealed class MacroList : Window, IDisposable private static void OpenEditor(Macro? macro) { var stats = Service.Plugin.GetDefaultStats(); - Service.Plugin.OpenMacroEditor(stats.Character, stats.Recipe, stats.Buffs, null, macro?.Actions ?? Enumerable.Empty(), macro != null ? (actions => { macro.ActionEnumerable = actions; Service.Configuration.Save(); }) : null); + Service.Plugin.OpenMacroEditor( + stats.Character, + stats.Recipe, + stats.Buffs, + null, + macro?.Actions ?? Enumerable.Empty(), + macro != null + ? ( + actions => + { + macro.ActionEnumerable = actions; + Service.Configuration.Save(); + } + ) + : null + ); } private void OnMacroChanged(Macro macro) diff --git a/Craftimizer/Windows/RecipeNote.cs b/Craftimizer/Windows/RecipeNote.cs index b7033b1..59d2002 100644 --- a/Craftimizer/Windows/RecipeNote.cs +++ b/Craftimizer/Windows/RecipeNote.cs @@ -1,8 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Runtime.InteropServices; using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using Craftimizer.Solver; using Craftimizer.Utils; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling.Payloads; @@ -20,13 +27,6 @@ using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.GUI; -using Dalamud.Bindings.ImGui; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Numerics; -using System.Runtime.InteropServices; using ActionType = Craftimizer.Simulator.Actions.ActionType; using ClassJob = Craftimizer.Simulator.ClassJob; using CSRecipeNote = FFXIVClientStructs.FFXIV.Client.Game.UI.RecipeNote; @@ -36,14 +36,14 @@ namespace Craftimizer.Windows; public sealed unsafe class RecipeNote : Window, IDisposable { - private const ImGuiWindowFlags WindowFlagsPinned = WindowFlagsFloating - | ImGuiWindowFlags.NoSavedSettings; + private const ImGuiWindowFlags WindowFlagsPinned = + WindowFlagsFloating | ImGuiWindowFlags.NoSavedSettings; private const ImGuiWindowFlags WindowFlagsFloating = - ImGuiWindowFlags.AlwaysAutoResize - | ImGuiWindowFlags.NoFocusOnAppearing; + ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoFocusOnAppearing; - private const string WindowNamePinned = "Craftimizer Crafting Log Helper###CraftimizerRecipeNote"; + private const string WindowNamePinned = + "Craftimizer Crafting Log Helper###CraftimizerRecipeNote"; private const string WindowNameFloating = $"{WindowNamePinned}Floating"; public enum CraftableStatus @@ -68,7 +68,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable private BackgroundTask<(Macro?, SimulationState?)>? SavedMacroTask { get; set; } private BackgroundTask? SuggestedMacroTask { get; set; } - private BackgroundTask<(CommunityMacros.CommunityMacro?, SimulationState?)>? CommunityMacroTask { get; set; } + private BackgroundTask<( + CommunityMacros.CommunityMacro?, + SimulationState? + )>? CommunityMacroTask { get; set; } private Solver.Solver? BestMacroSolver { get; set; } public bool HasSavedMacro { get; private set; } @@ -81,7 +84,8 @@ public sealed unsafe class RecipeNote : Window, IDisposable private ILoadedTextureIcon NoManipulationBadge { get; } private IFontHandle AxisFont { get; } - public RecipeNote() : base(WindowNamePinned) + public RecipeNote() + : base(WindowNamePinned) { ExpertBadge = IconManager.GetAssemblyTexture("Graphics.expert_badge.png"); CollectibleBadge = IconManager.GetAssemblyTexture("Graphics.collectible_badge.png"); @@ -89,7 +93,9 @@ public sealed unsafe class RecipeNote : Window, IDisposable SplendorousBadge = IconManager.GetAssemblyTexture("Graphics.splendorous.png"); SpecialistBadge = IconManager.GetAssemblyTexture("Graphics.specialist.png"); NoManipulationBadge = IconManager.GetAssemblyTexture("Graphics.no_manip.png"); - AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis14)); + AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle( + new(GameFontFamilyAndSize.Axis14) + ); RespectCloseHotkey = false; DisableWindowSounds = true; @@ -99,7 +105,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable SizeConstraints = new WindowSizeConstraints { MinimumSize = new(-1), - MaximumSize = new(10000, 10000) + MaximumSize = new(10000, 10000), }; TitleBarButtons = @@ -109,14 +115,15 @@ public sealed unsafe class RecipeNote : Window, IDisposable Icon = FontAwesomeIcon.Cog, IconOffset = new(2, 1), Click = _ => Service.Plugin.OpenSettingsTab("Crafting Log"), - ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings") + ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings"), }, - new() { + new() + { Icon = FontAwesomeIcon.Heart, IconOffset = new(2, 1), Click = _ => Util.OpenLink(Plugin.Plugin.SupportLink), - ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!") - } + ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!"), + }, ]; Service.WindowSystem.AddWindow(this); @@ -152,20 +159,35 @@ public sealed unsafe class RecipeNote : Window, IDisposable CalculateSavedMacro(); // If it didn't exist before or it already ran, we need to recalculate - if (Service.Configuration.SuggestMacroAutomatically && SuggestedMacroTask?.Result == null && (SuggestedMacroTask?.Completed ?? true)) + if ( + Service.Configuration.SuggestMacroAutomatically + && SuggestedMacroTask?.Result == null + && (SuggestedMacroTask?.Completed ?? true) + ) CalculateSuggestedMacro(); // If we don't want to suggest automatically, we should cancel and clean out the task - else if (!Service.Configuration.SuggestMacroAutomatically && SuggestedMacroTask?.Result == null) + else if ( + !Service.Configuration.SuggestMacroAutomatically + && SuggestedMacroTask?.Result == null + ) { SuggestedMacroTask?.Cancel(); SuggestedMacroTask = null; } // If it didn't exist before or it already ran, we need to recalculate - if (Service.Configuration.ShowCommunityMacros && Service.Configuration.SearchCommunityMacroAutomatically && CommunityMacroTask?.Result == null && (CommunityMacroTask?.Completed ?? true)) + if ( + Service.Configuration.ShowCommunityMacros + && Service.Configuration.SearchCommunityMacroAutomatically + && CommunityMacroTask?.Result == null + && (CommunityMacroTask?.Completed ?? true) + ) CalculateCommunityMacro(); // If we don't want to search automatically, we should cancel and clean out the task - else if (!Service.Configuration.SearchCommunityMacroAutomatically && CommunityMacroTask?.Result == null) + else if ( + !Service.Configuration.SearchCommunityMacroAutomatically + && CommunityMacroTask?.Result == null + ) { CommunityMacroTask?.Cancel(); CommunityMacroTask = null; @@ -184,10 +206,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable WasCalculatable = ShouldCalculate; } - public override bool DrawConditions() => - ShouldOpen; + public override bool DrawConditions() => ShouldOpen; private bool StatsChanged { get; set; } + private bool CalculateShouldOpen() { if (Service.Objects.LocalPlayer == null) @@ -258,17 +280,27 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var gearStats = Gearsets.CalculateGearsetCurrentStats(); - var container = InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems); + var container = InventoryManager + .Instance() + ->GetInventoryContainer(InventoryType.EquippedItems); if (container == null) return false; gearItems = Gearsets.GetGearsetItems(container); - var characterStats = Gearsets.CalculateCharacterStats(gearStats, gearItems, RecipeData.ClassJob.GetPlayerLevel(), RecipeData.ClassJob.CanPlayerUseManipulation()); + var characterStats = Gearsets.CalculateCharacterStats( + gearStats, + gearItems, + RecipeData.ClassJob.GetPlayerLevel(), + RecipeData.ClassJob.CanPlayerUseManipulation() + ); if (characterStats != CharacterStats) { // Re-initialize recipe data to recalculate adjusted level if needed - if (RecipeData.AdjustedJobLevel != null && characterStats.Level != CharacterStats?.Level) + if ( + RecipeData.AdjustedJobLevel != null + && characterStats.Level != CharacterStats?.Level + ) { RecipeData = new(RecipeData.RecipeId); } @@ -305,7 +337,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable } // If we want to search automatically, we should recalculate - if (Service.Configuration.ShowCommunityMacros && Service.Configuration.SearchCommunityMacroAutomatically) + if ( + Service.Configuration.ShowCommunityMacros + && Service.Configuration.SearchCommunityMacroAutomatically + ) CalculateCommunityMacro(); // Otherwise, we should cancel and clean out the task else @@ -324,13 +359,16 @@ public sealed unsafe class RecipeNote : Window, IDisposable throw new InvalidOperationException("RecipeData must not be null"); var ingredientCount = RecipeData.Ingredients.Count; - var ingredientSpan = MemoryMarshal.Cast(CSRecipeNote.Instance()->RecipeList->SelectedRecipe->Ingredients); + var ingredientSpan = MemoryMarshal.Cast( + CSRecipeNote.Instance()->RecipeList->SelectedRecipe->Ingredients + ); return ingredientSpan.ToArray().Take(ingredientCount).Select(i => (int)i.HQCount); } private Vector2? LastPosition { get; set; } private byte? StyleAlpha { get; set; } private byte? LastAlpha { get; set; } + public override void PreDraw() { base.PreDraw(); @@ -342,13 +380,16 @@ public sealed unsafe class RecipeNote : Window, IDisposable ref var unit = ref *Addon; var scale = unit.Scale; var pos = new Vector2(unit.X, unit.Y); - var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale; + var size = + new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) + * scale; var newAlpha = unit.WindowNode->AtkResNode.Alpha_2; StyleAlpha = LastAlpha ?? newAlpha; LastAlpha = newAlpha; - uint nodeId, nodeParentId; + uint nodeId, + nodeParentId; if (IsWKS) { nodeId = 15; @@ -377,7 +418,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable WindowName = WindowNameFloating; } - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, StyleAlpha.HasValue ? (StyleAlpha.Value / 255f) : 1); + ImGui.PushStyleVar( + ImGuiStyleVar.Alpha, + StyleAlpha.HasValue ? (StyleAlpha.Value / 255f) : 1 + ); } public override void PostDraw() @@ -392,14 +436,30 @@ public sealed unsafe class RecipeNote : Window, IDisposable IsCollapsed = false; var availWidth = ImGui.GetContentRegionAvail().X; - using (var table = ImRaii.Table("stats", 2, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingFixedSame | ImGuiTableFlags.NoSavedSettings)) + using ( + var table = ImRaii.Table( + "stats", + 2, + ImGuiTableFlags.BordersInnerV + | ImGuiTableFlags.SizingFixedSame + | ImGuiTableFlags.NoSavedSettings + ) + ) { if (table) { if (StatsChanged) { - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 150 * ImGuiHelpers.GlobalScale); - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 150 * ImGuiHelpers.GlobalScale); + ImGui.TableSetupColumn( + "", + ImGuiTableColumnFlags.WidthFixed, + 150 * ImGuiHelpers.GlobalScale + ); + ImGui.TableSetupColumn( + "", + ImGuiTableColumnFlags.WidthFixed, + 150 * ImGuiHelpers.GlobalScale + ); } ImGui.TableNextColumn(); @@ -410,7 +470,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable // Ensure that we know the window should be the same size as this table. Any more and it'll grow slowly and won't shrink when it could ImGui.SameLine(0, 0); // The -1 is to account for the extra vertical separator on the right that ImGui draws for some reason - availWidth = ImGui.GetCursorPosX() - ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().CellPadding.X - 1; + availWidth = + ImGui.GetCursorPosX() + - ImGui.GetStyle().WindowPadding.X + + ImGui.GetStyle().CellPadding.X + - 1; } } @@ -434,7 +498,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable State = macroTaskResult?.Item2, }; if (macroTaskResult is { } macro && macro.Item1 is { } savedMacro) - state.MacroEditorSetter = a => { savedMacro.ActionEnumerable = a; Service.Configuration.Save(); }; + state.MacroEditorSetter = a => + { + savedMacro.ActionEnumerable = a; + Service.Configuration.Save(); + }; DrawMacro(in state, panelWidth); } @@ -476,7 +544,14 @@ public sealed unsafe class RecipeNote : Window, IDisposable Service.Plugin.OpenMacroListWindow(); if (ImGui.Button("Open in Macro Editor", new(availWidth, 0))) - Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), [], null); + Service.Plugin.OpenMacroEditor( + CharacterStats!, + RecipeData!, + new(Service.Objects.LocalPlayer!.StatusList), + CalculateIngredientHqCounts(), + [], + null + ); } private void DrawCharacterStats() @@ -491,22 +566,29 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (level != 0) levelText = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(level); var imageSize = ImGui.GetFrameHeight(); - bool hasSplendorous = false, hasSpecialist = false, shouldHaveManip = false; - if (CraftStatus is not (CraftableStatus.LockedClassJob or CraftableStatus.WrongClassJob)) + bool hasSplendorous = false, + hasSpecialist = false, + shouldHaveManip = false; + if ( + CraftStatus is not (CraftableStatus.LockedClassJob or CraftableStatus.WrongClassJob) + ) { hasSplendorous = CharacterStats!.HasSplendorousBuff; hasSpecialist = CharacterStats!.IsSpecialist; - shouldHaveManip = !CharacterStats.CanUseManipulation && CharacterStats.Level >= ActionType.Manipulation.Level(); + shouldHaveManip = + !CharacterStats.CanUseManipulation + && CharacterStats.Level >= ActionType.Manipulation.Level(); } ImGuiUtils.AlignCentered( - imageSize + 5 + - textClassSize.X + - (level == 0 ? 0 : (3 + ImGui.CalcTextSize(levelText).X)) + - (hasSplendorous ? (3 + imageSize) : 0) + - (hasSpecialist ? (3 + imageSize) : 0) + - (shouldHaveManip ? (3 + imageSize) : 0) - ); + imageSize + + 5 + + textClassSize.X + + (level == 0 ? 0 : (3 + ImGui.CalcTextSize(levelText).X)) + + (hasSplendorous ? (3 + imageSize) : 0) + + (hasSpecialist ? (3 + imageSize) : 0) + + (shouldHaveManip ? (3 + imageSize) : 0) + ); ImGui.AlignTextToFramePadding(); var uv0 = new Vector2(6, 3); @@ -514,7 +596,12 @@ public sealed unsafe class RecipeNote : Window, IDisposable uv0 /= new Vector2(56); uv1 /= new Vector2(56); - ImGui.Image(Service.IconManager.GetIconCached(RecipeData.ClassJob.GetIconId()).Handle, new Vector2(imageSize), uv0, uv1); + ImGui.Image( + Service.IconManager.GetIconCached(RecipeData.ClassJob.GetIconId()).Handle, + new Vector2(imageSize), + uv0, + uv1 + ); ImGui.SameLine(0, 5); if (level != 0) @@ -536,7 +623,13 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (hasSpecialist) { ImGui.SameLine(0, 3); - ImGui.Image(SpecialistBadge.Handle, new Vector2(imageSize), Vector2.Zero, Vector2.One, new(0.99f, 0.97f, 0.62f, 1f)); + ImGui.Image( + SpecialistBadge.Handle, + new Vector2(imageSize), + Vector2.Zero, + Vector2.One, + new(0.99f, 0.97f, 0.62f, 1f) + ); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Specialist"); } @@ -556,13 +649,19 @@ public sealed unsafe class RecipeNote : Window, IDisposable { case CraftableStatus.LockedClassJob: { - ImGuiUtils.TextCentered($"You do not have {RecipeData.ClassJob.GetName()} unlocked."); + ImGuiUtils.TextCentered( + $"You do not have {RecipeData.ClassJob.GetName()} unlocked." + ); ImGui.Separator(); var unlockQuest = RecipeData.ClassJob.GetUnlockQuest(); - var (questGiver, questTerritory, questLocation, mapPayload) = ResolveLevelData(unlockQuest.IssuerLocation.RowId); + var (questGiver, questTerritory, questLocation, mapPayload) = ResolveLevelData( + unlockQuest.IssuerLocation.RowId + ); var unlockText = $"Unlock it from {questGiver}"; - ImGuiUtils.AlignCentered(ImGui.CalcTextSize(unlockText).X + 5 + ImGui.GetFrameHeight()); + ImGuiUtils.AlignCentered( + ImGui.CalcTextSize(unlockText).X + 5 + ImGui.GetFrameHeight() + ); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(unlockText); ImGui.SameLine(0, 5); @@ -571,12 +670,16 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip("Open in map"); - ImGuiUtils.TextCentered($"{questTerritory} ({GetCoordinatesString(questLocation)})"); + ImGuiUtils.TextCentered( + $"{questTerritory} ({GetCoordinatesString(questLocation)})" + ); } break; case CraftableStatus.WrongClassJob: { - ImGuiUtils.TextCentered($"You are not {RecipeData.ClassJob.GetNameArticle()} {RecipeData.ClassJob.GetName()}."); + ImGuiUtils.TextCentered( + $"You are not {RecipeData.ClassJob.GetNameArticle()} {RecipeData.ClassJob.GetName()}." + ); var gearsetId = GetGearsetForJob(RecipeData.ClassJob); if (gearsetId.HasValue) { @@ -586,7 +689,9 @@ public sealed unsafe class RecipeNote : Window, IDisposable ImGuiUtils.Tooltip($"Swap to gearset {gearsetId + 1}"); } else - ImGuiUtils.TextCentered($"You do not have any {RecipeData.ClassJob.GetName()} gearsets."); + ImGuiUtils.TextCentered( + $"You do not have any {RecipeData.ClassJob.GetName()} gearsets." + ); ImGui.Dummy(default); } break; @@ -594,10 +699,14 @@ public sealed unsafe class RecipeNote : Window, IDisposable { ImGuiUtils.TextCentered($"You need to be a specialist to craft this recipe."); - var (vendorName, vendorTerritory, vendorLoation, mapPayload) = ResolveLevelData(5891399); + var (vendorName, vendorTerritory, vendorLoation, mapPayload) = ResolveLevelData( + 5891399 + ); var unlockText = $"Trade a Soul of the Crafter to {vendorName}"; - ImGuiUtils.AlignCentered(ImGui.CalcTextSize(unlockText).X + 5 + ImGui.GetFrameHeight()); + ImGuiUtils.AlignCentered( + ImGui.CalcTextSize(unlockText).X + 5 + ImGui.GetFrameHeight() + ); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(unlockText); ImGui.SameLine(0, 5); @@ -606,7 +715,9 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip("Open in map"); - ImGuiUtils.TextCentered($"{vendorTerritory} ({GetCoordinatesString(vendorLoation)})"); + ImGuiUtils.TextCentered( + $"{vendorTerritory} ({GetCoordinatesString(vendorLoation)})" + ); } break; case CraftableStatus.RequiredItem: @@ -618,7 +729,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable ImGuiUtils.TextCentered($"You are missing the required equipment."); ImGuiUtils.AlignCentered(imageSize + 5 + ImGui.CalcTextSize(itemName).X); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIconCached(item.Icon).Handle, new(imageSize)); + ImGui.Image( + Service.IconManager.GetIconCached(item.Icon).Handle, + new(imageSize) + ); ImGui.SameLine(0, 5); ImGui.TextUnformatted(itemName); } @@ -628,7 +742,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable var status = RecipeData.Recipe.StatusRequired.Value!; var statusName = status.Name.ToString(); var statusIcon = Service.IconManager.GetIconCached(status.Icon); - var imageSize = new Vector2(ImGui.GetFrameHeight() * (statusIcon.AspectRatio ?? 1), ImGui.GetFrameHeight()); + var imageSize = new Vector2( + ImGui.GetFrameHeight() * (statusIcon.AspectRatio ?? 1), + ImGui.GetFrameHeight() + ); ImGuiUtils.TextCentered($"You are missing the required status effect."); ImGuiUtils.AlignCentered(imageSize.X + 5 + ImGui.CalcTextSize(statusName).X); @@ -642,14 +759,20 @@ public sealed unsafe class RecipeNote : Window, IDisposable { ImGuiUtils.TextCentered("Your Craftsmanship is too low."); - DrawRequiredStatsTable(CharacterStats!.Craftsmanship, RecipeData.Recipe.RequiredCraftsmanship); + DrawRequiredStatsTable( + CharacterStats!.Craftsmanship, + RecipeData.Recipe.RequiredCraftsmanship + ); } break; case CraftableStatus.ControlTooLow: { ImGuiUtils.TextCentered("Your Control is too low."); - DrawRequiredStatsTable(CharacterStats!.Control, RecipeData.Recipe.RequiredControl); + DrawRequiredStatsTable( + CharacterStats!.Control, + RecipeData.Recipe.RequiredControl + ); } break; case CraftableStatus.OK: @@ -657,7 +780,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable using var table = ImRaii.Table("characterStats", 2); if (table) { - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale); + ImGui.TableSetupColumn( + "", + ImGuiTableColumnFlags.WidthFixed, + 100 * ImGuiHelpers.GlobalScale + ); ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthStretch); ImGui.TableNextColumn(); @@ -694,7 +821,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable { textStarsSize = AxisFont.CalcTextSize(textStars); } - var textLevel = SqText.LevelPrefix.ToIconChar() + SqText.ToLevelString(RecipeData.AdjustedJobLevel ?? RecipeData.RecipeInfo.ClassJobLevel); + var textLevel = + SqText.LevelPrefix.ToIconChar() + + SqText.ToLevelString( + RecipeData.AdjustedJobLevel ?? RecipeData.RecipeInfo.ClassJobLevel + ); var isExpert = RecipeData.RecipeInfo.IsExpert; var isCollectable = RecipeData.IsCollectable; var isAdjustable = RecipeData.AdjustedJobLevel.HasValue; @@ -704,16 +835,20 @@ public sealed unsafe class RecipeNote : Window, IDisposable var badgeOffset = (imageSize - badgeSize.Y) / 2; ImGuiUtils.AlignCentered( - imageSize + 5 + - ImGui.CalcTextSize(textLevel).X + - (textStarsSize != Vector2.Zero ? textStarsSize.X + 3 : 0) + - (isAdjustable ? imageSize + 3 : 0) + - (isCollectable ? badgeSize.X + 3 : 0) + - (isExpert ? badgeSize.X + 3 : 0) - ); + imageSize + + 5 + + ImGui.CalcTextSize(textLevel).X + + (textStarsSize != Vector2.Zero ? textStarsSize.X + 3 : 0) + + (isAdjustable ? imageSize + 3 : 0) + + (isCollectable ? badgeSize.X + 3 : 0) + + (isExpert ? badgeSize.X + 3 : 0) + ); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value!.Icon).Handle, new Vector2(imageSize)); + ImGui.Image( + Service.IconManager.GetIconCached(RecipeData.Recipe.ItemResult.Value!.Icon).Handle, + new Vector2(imageSize) + ); ImGui.SameLine(0, 5); ImGui.TextUnformatted(textLevel); @@ -759,7 +894,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable using var table = ImRaii.Table("recipeStats", 2); if (table) { - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale); + ImGui.TableSetupColumn( + "", + ImGuiTableColumnFlags.WidthFixed, + 100 * ImGuiHelpers.GlobalScale + ); ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthStretch); ImGui.TableNextColumn(); @@ -783,8 +922,9 @@ public sealed unsafe class RecipeNote : Window, IDisposable { Saved, Suggested, - Community + Community, } + private record struct MacroTaskState { public MacroTaskType Type; @@ -806,7 +946,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable MacroTaskType.Saved => "Best Saved Macro", MacroTaskType.Suggested => "Suggested Macro", MacroTaskType.Community => "Best Community Macro", - _ => throw new ArgumentOutOfRangeException(nameof(state), "state.Type must have a valid type") + _ => throw new ArgumentOutOfRangeException( + nameof(state), + "state.Type must have a valid type" + ), }; using var panel = ImRaii2.GroupPanel(panelTitle, panelWidth, out _); @@ -822,37 +965,60 @@ public sealed unsafe class RecipeNote : Window, IDisposable switch (state.Type) { case MacroTaskType.Saved: - throw new InvalidOperationException("Saved macro window should always be started or completed"); + throw new InvalidOperationException( + "Saved macro window should always be started or completed" + ); case MacroTaskType.Suggested: - { - using var _padding = ImRaii.PushStyle(ImGuiStyleVar.FramePadding, ImGui.GetStyle().FramePadding * 2); - var size = ImGui.CalcTextSize("Generate") + ImGui.GetStyle().FramePadding * 2; - var c = ImGui.GetCursorPos(); - var availSize = new Vector2(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight); - ImGuiUtils.AlignMiddle(size, availSize); - if (ImGui.Button("Generate")) - CalculateSuggestedMacro(); - if (ImGui.IsItemHovered()) - ImGuiUtils.TooltipWrapped("Suggest a way to finish the crafting recipe. " + - "Results aren't perfect, and levels of success " + - "can vary wildly depending on the solver's settings."); - ImGui.SetCursorPos(c + new Vector2(0, availSize.Y + ImGui.GetStyle().ItemSpacing.Y)); - break; - } + { + using var _padding = ImRaii.PushStyle( + ImGuiStyleVar.FramePadding, + ImGui.GetStyle().FramePadding * 2 + ); + var size = ImGui.CalcTextSize("Generate") + ImGui.GetStyle().FramePadding * 2; + var c = ImGui.GetCursorPos(); + var availSize = new Vector2( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + ); + ImGuiUtils.AlignMiddle(size, availSize); + if (ImGui.Button("Generate")) + CalculateSuggestedMacro(); + if (ImGui.IsItemHovered()) + ImGuiUtils.TooltipWrapped( + "Suggest a way to finish the crafting recipe. " + + "Results aren't perfect, and levels of success " + + "can vary wildly depending on the solver's settings." + ); + ImGui.SetCursorPos( + c + new Vector2(0, availSize.Y + ImGui.GetStyle().ItemSpacing.Y) + ); + break; + } case MacroTaskType.Community: - { - using var _padding = ImRaii.PushStyle(ImGuiStyleVar.FramePadding, ImGui.GetStyle().FramePadding * 2); - var size = ImGui.CalcTextSize("Search Online") + ImGui.GetStyle().FramePadding * 2; - var c = ImGui.GetCursorPos(); - var availSize = new Vector2(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight); - ImGuiUtils.AlignMiddle(size, availSize); - if (ImGui.Button("Search Online")) - CalculateCommunityMacro(); - if (ImGui.IsItemHovered()) - ImGuiUtils.TooltipWrapped("Searches FFXIV Teamcraft to find you the best macro"); - ImGui.SetCursorPos(c + new Vector2(0, availSize.Y + ImGui.GetStyle().ItemSpacing.Y)); - break; - } + { + using var _padding = ImRaii.PushStyle( + ImGuiStyleVar.FramePadding, + ImGui.GetStyle().FramePadding * 2 + ); + var size = + ImGui.CalcTextSize("Search Online") + ImGui.GetStyle().FramePadding * 2; + var c = ImGui.GetCursorPos(); + var availSize = new Vector2( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + ); + ImGuiUtils.AlignMiddle(size, availSize); + if (ImGui.Button("Search Online")) + CalculateCommunityMacro(); + if (ImGui.IsItemHovered()) + ImGuiUtils.TooltipWrapped( + "Searches FFXIV Teamcraft to find you the best macro" + ); + ImGui.SetCursorPos( + c + new Vector2(0, availSize.Y + ImGui.GetStyle().ItemSpacing.Y) + ); + break; + } } } else if (!state.Completed) @@ -860,51 +1026,73 @@ public sealed unsafe class RecipeNote : Window, IDisposable switch (state.Type) { case MacroTaskType.Saved: - ImGuiUtils.TextMiddleNewLine("Calculating...", new(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight + 1)); + ImGuiUtils.TextMiddleNewLine( + "Calculating...", + new( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + 1 + ) + ); break; case MacroTaskType.Suggested: + { + if (state.Solver is not { } solver) + throw new ArgumentNullException(nameof(state), "Solver should not be null"); + + var calcTextSize = ImGui.CalcTextSize("Calculating..."); + var spacing = ImGui.GetStyle().ItemSpacing.X; + var fraction = Math.Clamp( + (float)solver.ProgressValue / solver.ProgressMax, + 0, + 1 + ); + + var c = ImGui.GetCursorPos(); + ImGuiUtils.AlignCentered( + windowHeight + spacing + calcTextSize.X, + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset + ); + + if (Service.Configuration.ProgressType == Configuration.ProgressBarType.None) { - if (state.Solver is not { } solver) - throw new ArgumentNullException(nameof(state), "Solver should not be null"); - - var calcTextSize = ImGui.CalcTextSize("Calculating..."); - var spacing = ImGui.GetStyle().ItemSpacing.X; - var fraction = Math.Clamp((float)solver.ProgressValue / solver.ProgressMax, 0, 1); - - var c = ImGui.GetCursorPos(); - ImGuiUtils.AlignCentered(windowHeight + spacing + calcTextSize.X, ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset); - - if (Service.Configuration.ProgressType == Configuration.ProgressBarType.None) - { - var textSize = ImGui.CalcTextSize($"{fraction * 100:N0}%"); - var cursor = ImGui.GetCursorPos(); - ImGuiUtils.AlignMiddle(textSize, new(windowHeight)); - ImGui.TextUnformatted($"{fraction * 100:N0}%"); - ImGui.SetCursorPos(cursor); - ImGui.Dummy(new Vector2(windowHeight + 4)); - } - else - { - var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage); - ImGuiUtils.ArcProgress( - solver.IsIndeterminate ? (float)-ImGui.GetTime() : fraction, - windowHeight / 2f + 2, - .5f, - ImGui.ColorConvertFloat4ToU32(progressColors.Background), - ImGui.ColorConvertFloat4ToU32(progressColors.Foreground)); - } - if (ImGui.IsItemHovered()) - DynamicBars.DrawProgressBarTooltip(solver); - - ImGui.SameLine(0, spacing); - - ImGuiUtils.AlignMiddle(calcTextSize, new(calcTextSize.X, windowHeight)); - ImGui.TextUnformatted("Calculating..."); - ImGui.SetCursorPos(c + new Vector2(0, windowHeight + ImGui.GetStyle().ItemSpacing.Y - 1)); - break; + var textSize = ImGui.CalcTextSize($"{fraction * 100:N0}%"); + var cursor = ImGui.GetCursorPos(); + ImGuiUtils.AlignMiddle(textSize, new(windowHeight)); + ImGui.TextUnformatted($"{fraction * 100:N0}%"); + ImGui.SetCursorPos(cursor); + ImGui.Dummy(new Vector2(windowHeight + 4)); } + else + { + var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage); + ImGuiUtils.ArcProgress( + solver.IsIndeterminate ? (float)-ImGui.GetTime() : fraction, + windowHeight / 2f + 2, + .5f, + ImGui.ColorConvertFloat4ToU32(progressColors.Background), + ImGui.ColorConvertFloat4ToU32(progressColors.Foreground) + ); + } + if (ImGui.IsItemHovered()) + DynamicBars.DrawProgressBarTooltip(solver); + + ImGui.SameLine(0, spacing); + + ImGuiUtils.AlignMiddle(calcTextSize, new(calcTextSize.X, windowHeight)); + ImGui.TextUnformatted("Calculating..."); + ImGui.SetCursorPos( + c + new Vector2(0, windowHeight + ImGui.GetStyle().ItemSpacing.Y - 1) + ); + break; + } case MacroTaskType.Community: - ImGuiUtils.TextMiddleNewLine("Searching...", new(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight + 1)); + ImGuiUtils.TextMiddleNewLine( + "Searching...", + new( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + 1 + ) + ); break; } } @@ -921,13 +1109,25 @@ public sealed unsafe class RecipeNote : Window, IDisposable switch (state.Type) { case MacroTaskType.Saved: - ImGuiUtils.TextMiddleNewLine("You have no macros!", new(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight + 1)); + ImGuiUtils.TextMiddleNewLine( + "You have no macros!", + new( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + 1 + ) + ); break; case MacroTaskType.Suggested: // Cancelled? break; case MacroTaskType.Community: - ImGuiUtils.TextMiddleNewLine("No macros found!", new(ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, windowHeight + 1)); + ImGuiUtils.TextMiddleNewLine( + "No macros found!", + new( + ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset, + windowHeight + 1 + ) + ); break; } } @@ -948,7 +1148,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable ImGuiUtils.TextCentered(macroName, panelWidth); } - using var table = ImRaii.Table("table", 3, ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame); + using var table = ImRaii.Table( + "table", + 3, + ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingStretchSame + ); if (table) { ImGui.TableSetupColumn("desc", ImGuiTableColumnFlags.WidthFixed, 0); @@ -965,73 +1169,102 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (Service.Configuration.ShowOptimalMacroStat) { var progressHeight = windowHeight; - if (simState.Progress >= simState.Input.Recipe.MaxProgress && simState.Input.Recipe.MaxQuality > 0) + if ( + simState.Progress >= simState.Input.Recipe.MaxProgress + && simState.Input.Recipe.MaxQuality > 0 + ) { ImGuiUtils.ArcProgress( - (float)simState.Quality / simState.Input.Recipe.MaxQuality, - progressHeight / 2f, - .5f, - ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Quality)); + (float)simState.Quality / simState.Input.Recipe.MaxQuality, + progressHeight / 2f, + .5f, + ImGui.GetColorU32(ImGuiCol.TableBorderLight), + ImGui.GetColorU32(Colors.Quality) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Quality: {simState.Quality} / {simState.Input.Recipe.MaxQuality}"); + ImGuiUtils.Tooltip( + $"Quality: {simState.Quality} / {simState.Input.Recipe.MaxQuality}" + ); } else { ImGuiUtils.ArcProgress( - (float)simState.Progress / simState.Input.Recipe.MaxProgress, - progressHeight / 2f, - .5f, - ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Progress)); + (float)simState.Progress / simState.Input.Recipe.MaxProgress, + progressHeight / 2f, + .5f, + ImGui.GetColorU32(ImGuiCol.TableBorderLight), + ImGui.GetColorU32(Colors.Progress) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Progress: {simState.Progress} / {simState.Input.Recipe.MaxProgress}"); + ImGuiUtils.Tooltip( + $"Progress: {simState.Progress} / {simState.Input.Recipe.MaxProgress}" + ); } } else { ImGuiUtils.ArcProgress( - (float)simState.Progress / simState.Input.Recipe.MaxProgress, + (float)simState.Progress / simState.Input.Recipe.MaxProgress, miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Progress)); + ImGui.GetColorU32(Colors.Progress) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Progress: {simState.Progress} / {simState.Input.Recipe.MaxProgress}"); + ImGuiUtils.Tooltip( + $"Progress: {simState.Progress} / {simState.Input.Recipe.MaxProgress}" + ); ImGui.SameLine(0, spacing); ImGuiUtils.ArcProgress( - (float)simState.Quality / simState.Input.Recipe.MaxQuality, + (float)simState.Quality / simState.Input.Recipe.MaxQuality, miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Quality)); + ImGui.GetColorU32(Colors.Quality) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Quality: {simState.Quality} / {simState.Input.Recipe.MaxQuality}"); - ImGuiUtils.ArcProgress((float)simState.Durability / simState.Input.Recipe.MaxDurability, - miniRowHeight / 2f, + ImGuiUtils.Tooltip( + $"Quality: {simState.Quality} / {simState.Input.Recipe.MaxQuality}" + ); + ImGuiUtils.ArcProgress( + (float)simState.Durability / simState.Input.Recipe.MaxDurability, + miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.Durability)); + ImGui.GetColorU32(Colors.Durability) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Remaining Durability: {simState.Durability} / {simState.Input.Recipe.MaxDurability}"); + ImGuiUtils.Tooltip( + $"Remaining Durability: {simState.Durability} / {simState.Input.Recipe.MaxDurability}" + ); ImGui.SameLine(0, spacing); ImGuiUtils.ArcProgress( - (float)simState.CP / simState.Input.Stats.CP, + (float)simState.CP / simState.Input.Stats.CP, miniRowHeight / 2f, .5f, ImGui.GetColorU32(ImGuiCol.TableBorderLight), - ImGui.GetColorU32(Colors.CP)); + ImGui.GetColorU32(Colors.CP) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"Remaining CP: {simState.CP} / {simState.Input.Stats.CP}"); + ImGuiUtils.Tooltip( + $"Remaining CP: {simState.CP} / {simState.Input.Stats.CP}" + ); } } ImGui.TableNextColumn(); { if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) - Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), actions, state.MacroEditorSetter); + Service.Plugin.OpenMacroEditor( + CharacterStats!, + RecipeData!, + new(Service.Objects.LocalPlayer!.StatusList), + CalculateIngredientHqCounts(), + actions, + state.MacroEditorSetter + ); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip("Open in Macro Editor"); if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight)) @@ -1042,7 +1275,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable ImGui.TableNextColumn(); { - var itemsPerRow = (int)MathF.Floor((ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset + spacing) / (miniRowHeight + spacing)); + var itemsPerRow = (int) + MathF.Floor( + (ImGui.GetContentRegionAvail().X - stepsAvailWidthOffset + spacing) + / (miniRowHeight + spacing) + ); var itemCount = actions.Count; for (var i = 0; i < itemsPerRow * 2; i++) { @@ -1053,7 +1290,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable var shouldShowMore = i + 1 == itemsPerRow * 2 && i + 1 < itemCount; if (!shouldShowMore) { - ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(miniRowHeight)); + ImGui.Image( + actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(miniRowHeight) + ); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip(actions[i].GetName(RecipeData!.ClassJob)); } @@ -1061,12 +1301,36 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var amtMore = itemCount - itemsPerRow * 2; var pos = ImGui.GetCursorPos(); - ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).Handle, new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); + ImGui.Image( + actions[i].GetIcon(RecipeData!.ClassJob).Handle, + new(miniRowHeight), + default, + Vector2.One, + new(1, 1, 1, .5f) + ); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip($"{actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more"); + ImGuiUtils.Tooltip( + $"{actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more" + ); ImGui.SetCursorPos(pos); - ImGui.GetWindowDrawList().AddRectFilled(ImGui.GetCursorScreenPos(), ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), ImGui.GetColorU32(ImGuiCol.FrameBg), miniRowHeight / 8f); - ImGui.GetWindowDrawList().AddTextClippedEx(ImGui.GetCursorScreenPos(), ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), $"+{amtMore}", null, new(.5f), null); + ImGui + .GetWindowDrawList() + .AddRectFilled( + ImGui.GetCursorScreenPos(), + ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), + ImGui.GetColorU32(ImGuiCol.FrameBg), + miniRowHeight / 8f + ); + ImGui + .GetWindowDrawList() + .AddTextClippedEx( + ImGui.GetCursorScreenPos(), + ImGui.GetCursorScreenPos() + new Vector2(miniRowHeight), + $"+{amtMore}", + null, + new(.5f), + null + ); } } else @@ -1084,7 +1348,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable using var table = ImRaii.Table("requiredStats", 2); if (table) { - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 100 * ImGuiHelpers.GlobalScale); + ImGui.TableSetupColumn( + "", + ImGuiTableColumnFlags.WidthFixed, + 100 * ImGuiHelpers.GlobalScale + ); ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthStretch); ImGui.TableNextColumn(); @@ -1125,7 +1393,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable var statusRequired = RecipeData.Recipe.StatusRequired; if (statusRequired.RowId != 0 && statusRequired.IsValid) { - if (!Service.Objects.LocalPlayer!.StatusList.Any(s => s.StatusId == statusRequired.RowId)) + if ( + !Service.Objects.LocalPlayer!.StatusList.Any(s => + s.StatusId == statusRequired.RowId + ) + ) return CraftableStatus.RequiredStatus; } @@ -1138,13 +1410,23 @@ public sealed unsafe class RecipeNote : Window, IDisposable return CraftableStatus.OK; } - private static (string NpcName, string Territory, Vector2 MapLocation, MapLinkPayload Payload) ResolveLevelData(uint levelRowId) + private static ( + string NpcName, + string Territory, + Vector2 MapLocation, + MapLinkPayload Payload + ) ResolveLevelData(uint levelRowId) { var level = LuminaSheets.LevelSheet.GetRow(levelRowId); var placeName = level.Territory.Value.PlaceName.Value.Name.ToString(); var location = WorldToMap2(new(level.X, level.Z), level.Map.Value!); - return (ResolveNpcResidentName(level.Object.RowId), placeName, location, new(level.Territory.RowId, level.Map.RowId, location.X, location.Y)); + return ( + ResolveNpcResidentName(level.Object.RowId), + placeName, + location, + new(level.Territory.RowId, level.Map.RowId, location.X, location.Y) + ); } private static Vector2 WorldToMap2(Vector2 worldCoordinates, Lumina.Excel.Sheets.Map map) @@ -1188,7 +1470,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable var hasDelineations = Gearsets.HasDelineations(); SavedMacroTask = new(token => { - var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo, StartingQuality); + var input = new SimulationInput( + CharacterStats!, + RecipeData!.RecipeInfo, + StartingQuality + ); var state = new SimulationState(input); var config = Service.Configuration.RecipeNoteSolverConfig; var canUseDelineations = !Service.Configuration.CheckDelineations || hasDelineations; @@ -1205,7 +1491,12 @@ public sealed unsafe class RecipeNote : Window, IDisposable var bestSaved = macros .Select(macro => { - var (score, outState) = CommunityMacros.CommunityMacro.CalculateScore(macro.Actions, simulator, in state, in mctsConfig); + var (score, outState) = CommunityMacros.CommunityMacro.CalculateScore( + macro.Actions, + simulator, + in state, + in mctsConfig + ); return (macro, outState, score); }) .MaxBy(m => m.score); @@ -1223,7 +1514,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable var hasDelineations = Gearsets.HasDelineations(); SuggestedMacroTask = new(token => { - var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo, StartingQuality); + var input = new SimulationInput( + CharacterStats!, + RecipeData!.RecipeInfo, + StartingQuality + ); var state = new SimulationState(input); var config = Service.Configuration.RecipeNoteSolverConfig; var canUseDelineations = !Service.Configuration.CheckDelineations || hasDelineations; @@ -1252,7 +1547,11 @@ public sealed unsafe class RecipeNote : Window, IDisposable var hasDelineations = Gearsets.HasDelineations(); CommunityMacroTask = new(token => { - var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo, StartingQuality); + var input = new SimulationInput( + CharacterStats!, + RecipeData!.RecipeInfo, + StartingQuality + ); var state = new SimulationState(input); var config = Service.Configuration.RecipeNoteSolverConfig; var canUseDelineations = !Service.Configuration.CheckDelineations || hasDelineations; @@ -1260,7 +1559,10 @@ public sealed unsafe class RecipeNote : Window, IDisposable config = config.FilterSpecialistActions(); var mctsConfig = new MCTSConfig(config); var simulator = new SimulatorNoRandom(); - var macros = Service.CommunityMacros.RetrieveRotations((int)RecipeData.Table.RowId, token).GetAwaiter().GetResult(); + var macros = Service + .CommunityMacros.RetrieveRotations((int)RecipeData.Table.RowId, token) + .GetAwaiter() + .GetResult(); token.ThrowIfCancellationRequested(); @@ -1269,7 +1571,12 @@ public sealed unsafe class RecipeNote : Window, IDisposable var bestSaved = macros .Select(macro => { - var (score, outState) = CommunityMacros.CommunityMacro.CalculateScore(macro.Actions, simulator, in state, in mctsConfig); + var (score, outState) = CommunityMacros.CommunityMacro.CalculateScore( + macro.Actions, + simulator, + in state, + in mctsConfig + ); return (macro, outState, score); }) .MaxBy(m => m.score); diff --git a/Craftimizer/Windows/Settings.cs b/Craftimizer/Windows/Settings.cs index 69422ef..01beb20 100644 --- a/Craftimizer/Windows/Settings.cs +++ b/Craftimizer/Windows/Settings.cs @@ -1,6 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using Craftimizer.Solver; +using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.ManagedFontAtlas; @@ -8,12 +14,6 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using FFXIVClientStructs.FFXIV.Client.UI; -using Dalamud.Bindings.ImGui; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; namespace Craftimizer.Plugin.Windows; @@ -31,17 +31,22 @@ public sealed class Settings : Window, IDisposable private IFontHandle HeaderFont { get; } private IFontHandle SubheaderFont { get; } - public Settings() : base("Craftimizer Settings", WindowFlags) + public Settings() + : base("Craftimizer Settings", WindowFlags) { Service.WindowSystem.AddWindow(this); - HeaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 2f))); - SubheaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 1.5f))); + HeaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => + e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 2f)) + ); + SubheaderFont = Service.PluginInterface.UiBuilder.FontAtlas.NewDelegateFontHandle(e => + e.OnPreBuild(tk => tk.AddDalamudDefaultFont(UiBuilder.DefaultFontSizePx * 1.5f)) + ); SizeConstraints = new WindowSizeConstraints() { MinimumSize = new(450, 400), - MaximumSize = new(float.PositiveInfinity) + MaximumSize = new(float.PositiveInfinity), }; } @@ -61,7 +66,13 @@ public sealed class Settings : Window, IDisposable return ImRaii.TabItem(label); } - private static void DrawOption(string label, string tooltip, bool val, Action setter, ref bool isDirty) + private static void DrawOption( + string label, + string tooltip, + bool val, + Action setter, + ref bool isDirty + ) { if (ImGui.Checkbox(label, ref val)) { @@ -72,12 +83,28 @@ public sealed class Settings : Window, IDisposable ImGuiUtils.TooltipWrapped(tooltip); } - private static void DrawOption(string label, string tooltip, T value, T min, T max, Action setter, ref bool isDirty) where T : struct, INumber + private static void DrawOption( + string label, + string tooltip, + T value, + T min, + T max, + Action setter, + ref bool isDirty + ) + where T : struct, INumber { ImGui.SetNextItemWidth(OptionWidth); var text = value.ToString(); ArgumentNullException.ThrowIfNull(text, nameof(value)); - if (ImGui.InputText(label, ref text, 8, ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal)) + if ( + ImGui.InputText( + label, + ref text, + 8, + ImGuiInputTextFlags.AutoSelectAll | ImGuiInputTextFlags.CharsDecimal + ) + ) { if (T.TryParse(text, null, out var newValue)) { @@ -102,7 +129,13 @@ public sealed class Settings : Window, IDisposable ImGuiUtils.TooltipWrapped(tooltip); } - private static void DrawOption(string label, string tooltip, string value, Action setter, ref bool isDirty) + private static void DrawOption( + string label, + string tooltip, + string value, + Action setter, + ref bool isDirty + ) { ImGui.SetNextItemWidth(OptionWidth); var text = value; @@ -118,7 +151,17 @@ public sealed class Settings : Window, IDisposable ImGuiUtils.TooltipWrapped(tooltip); } - private static void DrawOption(string label, string tooltip, Func getName, Func getTooltip, T value, Action setter, ref bool isDirty, params T[] excludedValues) where T : struct, Enum + private static void DrawOption( + string label, + string tooltip, + Func getName, + Func getTooltip, + T value, + Action setter, + ref bool isDirty, + params T[] excludedValues + ) + where T : struct, Enum { ImGui.SetNextItemWidth(OptionWidth); using (var combo = ImRaii.Combo(label, getName(value))) @@ -160,16 +203,16 @@ public sealed class Settings : Window, IDisposable { SolverAlgorithm.Oneshot => "Run through all iterations and pick the best macro", SolverAlgorithm.OneshotForked => "Oneshot, but using multiple solvers simultaneously", - SolverAlgorithm.Stepwise => "Run through all iterations and pick the next best step, " + - "and repeat using previous steps as a starting point", + SolverAlgorithm.Stepwise => "Run through all iterations and pick the next best step, " + + "and repeat using previous steps as a starting point", SolverAlgorithm.StepwiseForked => "Stepwise, but using multiple solvers simultaneously", - SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " + - "selected from the solvers, and each one is equally " + - "used as a starting point", - SolverAlgorithm.Raphael => "Finds the best solution, every time. This solver has " + - "very different options compared to the rest, as it " + - "is designed using an entirely different algorithm.", - _ => "Unknown" + SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " + + "selected from the solvers, and each one is equally " + + "used as a starting point", + SolverAlgorithm.Raphael => "Finds the best solution, every time. This solver has " + + "very different options compared to the rest, as it " + + "is designed using an entirely different algorithm.", + _ => "Unknown", }; private static string GetCopyTypeName(MacroCopyConfiguration.CopyType type) => @@ -185,12 +228,16 @@ public sealed class Settings : Window, IDisposable private static string GetCopyTypeTooltip(MacroCopyConfiguration.CopyType type) => type switch { - MacroCopyConfiguration.CopyType.OpenWindow => "Open a dedicated window with all macros being copied. " + - "Copy, view, and choose at your own leisure.", - MacroCopyConfiguration.CopyType.CopyToMacro => "Copy directly to the game's macro system.", - MacroCopyConfiguration.CopyType.CopyToClipboard => "Copy to your clipboard. Macros are separated by a blank line.", - MacroCopyConfiguration.CopyType.CopyToMacroMate => "Copy directly to a Macro Mate macro. Requires the Macro Mate plugin.", - _ => "Unknown" + MacroCopyConfiguration.CopyType.OpenWindow => + "Open a dedicated window with all macros being copied. " + + "Copy, view, and choose at your own leisure.", + MacroCopyConfiguration.CopyType.CopyToMacro => + "Copy directly to the game's macro system.", + MacroCopyConfiguration.CopyType.CopyToClipboard => + "Copy to your clipboard. Macros are separated by a blank line.", + MacroCopyConfiguration.CopyType.CopyToMacroMate => + "Copy directly to a Macro Mate macro. Requires the Macro Mate plugin.", + _ => "Unknown", }; private static string GetProgressBarTypeName(Configuration.ProgressBarType type) => @@ -207,8 +254,9 @@ public sealed class Settings : Window, IDisposable { Configuration.ProgressBarType.Colorful => "Colorful, rainbow colors", Configuration.ProgressBarType.Simple => "Simple, grayscale colors", - Configuration.ProgressBarType.None => "No progress bar; only percent completion is shown", - _ => "Unknown" + Configuration.ProgressBarType.None => + "No progress bar; only percent completion is shown", + _ => "Unknown", }; public override void Draw() @@ -238,9 +286,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Enable Synthesis Helper", - "Adds a helper next to your synthesis window to help solve for the best craft. " + - "Extremely useful for expert recipes, where the condition can greatly affect " + - "which actions you take.", + "Adds a helper next to your synthesis window to help solve for the best craft. " + + "Extremely useful for expert recipes, where the condition can greatly affect " + + "which actions you take.", Config.EnableSynthHelper, v => Config.EnableSynthHelper = v, ref isDirty @@ -248,9 +296,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Show Only One Macro Stat in Crafting Log", - "Only one stat will be shown for a macro. If a craft will be finished, quality " + - "is shown. Otherwise, progress is shown. Durability and remaining CP will be " + - "hidden.", + "Only one stat will be shown for a macro. If a craft will be finished, quality " + + "is shown. Otherwise, progress is shown. Durability and remaining CP will be " + + "hidden.", Config.ShowOptimalMacroStat, v => Config.ShowOptimalMacroStat = v, ref isDirty @@ -258,8 +306,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Check For Delineations", - "Your inventory will be checked to ensure that you have delineations available " + - "before suggesting any specialist actions.", + "Your inventory will be checked to ensure that you have delineations available " + + "before suggesting any specialist actions.", Config.CheckDelineations, v => Config.CheckDelineations = v, ref isDirty @@ -267,9 +315,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Reliability Trial Count", - "When testing for reliability of a macro in the editor, this many trials will be " + - "run. You should set this value to at least 100 to get a reliable spread of data. " + - "If it's too low, you may not find an outlier, and the average might be skewed.", + "When testing for reliability of a macro in the editor, this many trials will be " + + "run. You should set this value to at least 100 to get a reliable spread of data. " + + "If it's too low, you may not find an outlier, and the average might be skewed.", Config.ReliabilitySimulationCount, 5, 5000, @@ -301,8 +349,13 @@ public sealed class Settings : Window, IDisposable ref isDirty ); - if (Config.MacroCopy.Type == MacroCopyConfiguration.CopyType.CopyToMacroMate && - !Service.PluginInterface.InstalledPlugins.Any(p => p.IsLoaded && string.Equals(p.InternalName, "MacroMate", StringComparison.Ordinal))) + if ( + Config.MacroCopy.Type == MacroCopyConfiguration.CopyType.CopyToMacroMate + && !Service.PluginInterface.InstalledPlugins.Any(p => + p.IsLoaded + && string.Equals(p.InternalName, "MacroMate", StringComparison.Ordinal) + ) + ) { ImGui.SameLine(); using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange)) @@ -326,8 +379,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Copy to Shared Macros", - "Copy to the shared macros tab. Leaving this unchecked copies to the " + - "individual tab.", + "Copy to the shared macros tab. Leaving this unchecked copies to the " + + "individual tab.", Config.MacroCopy.SharedMacro, v => Config.MacroCopy.SharedMacro = v, ref isDirty @@ -335,20 +388,22 @@ public sealed class Settings : Window, IDisposable DrawOption( "Macro Number", - "The # of the macro to being copying to. Subsequent macros will be " + - "copied relative to this macro.", + "The # of the macro to being copying to. Subsequent macros will be " + + "copied relative to this macro.", Config.MacroCopy.StartMacroIdx, - 0, 99, + 0, + 99, v => Config.MacroCopy.StartMacroIdx = v, ref isDirty ); DrawOption( "Max Macro Copy Count", - "The maximum number of macros to be copied. Any more and a window is " + - "displayed with the rest of them.", + "The maximum number of macros to be copied. Any more and a window is " + + "displayed with the rest of them.", Config.MacroCopy.MaxMacroCount, - 1, 99, + 1, + 99, v => Config.MacroCopy.MaxMacroCount = v, ref isDirty ); @@ -384,15 +439,20 @@ public sealed class Settings : Window, IDisposable { DrawOption( "Use Macro Chain", - "Replaces the last step with /nextmacro to run the next macro " + - "automatically. Overrides the Intermediate Notification Sound.", + "Replaces the last step with /nextmacro to run the next macro " + + "automatically. Overrides the Intermediate Notification Sound.", Config.MacroCopy.UseNextMacro, v => Config.MacroCopy.UseNextMacro = v, ref isDirty ); - if (Config.MacroCopy.UseNextMacro && - !Service.PluginInterface.InstalledPlugins.Any(p => p.IsLoaded && string.Equals(p.InternalName, "MacroChain", StringComparison.Ordinal))) + if ( + Config.MacroCopy.UseNextMacro + && !Service.PluginInterface.InstalledPlugins.Any(p => + p.IsLoaded + && string.Equals(p.InternalName, "MacroChain", StringComparison.Ordinal) + ) + ) { ImGui.SameLine(); using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange)) @@ -407,8 +467,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Add Macro Lock", - "Adds /mlock to the beginning of every macro. Prevents other " + - "macros from being run.", + "Adds /mlock to the beginning of every macro. Prevents other " + + "macros from being run.", Config.MacroCopy.UseMacroLock, v => Config.MacroCopy.UseMacroLock = v, ref isDirty @@ -424,12 +484,18 @@ public sealed class Settings : Window, IDisposable if (Config.MacroCopy.AddNotification) { - if ((Config.MacroCopy.Type == MacroCopyConfiguration.CopyType.CopyToMacro || !Config.MacroCopy.CombineMacro) && Config.MacroCopy.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate) + if ( + ( + Config.MacroCopy.Type == MacroCopyConfiguration.CopyType.CopyToMacro + || !Config.MacroCopy.CombineMacro + ) + && Config.MacroCopy.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate + ) { DrawOption( "Force Notification", - "Prioritize always having a notification sound at the end of " + - "every macro. Keeping this off prevents macros with only 1 action.", + "Prioritize always having a notification sound at the end of " + + "every macro. Keeping this off prevents macros with only 1 action.", Config.MacroCopy.ForceNotification, v => Config.MacroCopy.ForceNotification = v, ref isDirty @@ -446,14 +512,18 @@ public sealed class Settings : Window, IDisposable if (Config.MacroCopy.AddNotificationSound) { - if (!Config.MacroCopy.UseNextMacro && Config.MacroCopy.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate) + if ( + !Config.MacroCopy.UseNextMacro + && Config.MacroCopy.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate + ) { DrawOption( "Intermediate Notification Sound", - "Ending notification sound for an intermediary macro.\n" + - "Uses ", + "Ending notification sound for an intermediary macro.\n" + + "Uses ", Config.MacroCopy.IntermediateNotificationSound, - 1, 16, + 1, + 16, v => { Config.MacroCopy.IntermediateNotificationSound = v; @@ -465,10 +535,10 @@ public sealed class Settings : Window, IDisposable DrawOption( "Final Notification Sound", - "Ending notification sound for the final macro.\n" + - "Uses ", + "Ending notification sound for the final macro.\n" + "Uses ", Config.MacroCopy.EndNotificationSound, - 1, 16, + 1, + 16, v => { Config.MacroCopy.EndNotificationSound = v; @@ -506,7 +576,12 @@ public sealed class Settings : Window, IDisposable Config.Save(); } - private static void DrawSolverConfig(ref SolverConfig configRef, SolverConfig defaultConfig, bool disableOptimal, out bool isDirty) + private static void DrawSolverConfig( + ref SolverConfig configRef, + SolverConfig defaultConfig, + bool disableOptimal, + out bool isDirty + ) { isDirty = false; @@ -522,10 +597,10 @@ public sealed class Settings : Window, IDisposable DrawOption( "Algorithm", - "The algorithm to use when solving for a macro. Different " + - "algorithms provide different pros and cons for using them. " + - "By far, the Optimal and Stepwise Genetic algorithms provide " + - "the best results, especially for very difficult crafts.", + "The algorithm to use when solving for a macro. Different " + + "algorithms provide different pros and cons for using them. " + + "By far, the Optimal and Stepwise Genetic algorithms provide " + + "the best results, especially for very difficult crafts.", GetAlgorithmName, GetAlgorithmTooltip, config.Algorithm, @@ -534,15 +609,25 @@ public sealed class Settings : Window, IDisposable disableOptimal ? [SolverAlgorithm.Raphael] : [] ); - using (ImRaii.Disabled(config.Algorithm is not (SolverAlgorithm.OneshotForked or SolverAlgorithm.StepwiseForked or SolverAlgorithm.StepwiseGenetic or SolverAlgorithm.Raphael))) + using ( + ImRaii.Disabled( + config.Algorithm + is not ( + SolverAlgorithm.OneshotForked + or SolverAlgorithm.StepwiseForked + or SolverAlgorithm.StepwiseGenetic + or SolverAlgorithm.Raphael + ) + ) + ) DrawOption( "Max Core Count", - "The number of cores to use when solving. You should use as many " + - "as you can. If it's too high, it will have an effect on your gameplay " + - $"experience. A good estimate would be 1 or 2 cores less than your " + - $"system (FYI, you have {Environment.ProcessorCount} cores), but make sure to accomodate " + - $"for any other tasks you have in the background, if you have any.\n" + - "(Only used in the Forked, Genetic, and Optimal algorithms)", + "The number of cores to use when solving. You should use as many " + + "as you can. If it's too high, it will have an effect on your gameplay " + + $"experience. A good estimate would be 1 or 2 cores less than your " + + $"system (FYI, you have {Environment.ProcessorCount} cores), but make sure to accomodate " + + $"for any other tasks you have in the background, if you have any.\n" + + "(Only used in the Forked, Genetic, and Optimal algorithms)", config.MaxThreadCount, 1, Environment.ProcessorCount, @@ -554,10 +639,10 @@ public sealed class Settings : Window, IDisposable { DrawOption( "Target Iterations", - "The total number of iterations to run per crafting step. " + - "Higher values require more computational power. Higher values " + - "also may decrease variance, so other values should be tweaked " + - "as necessary to get a more favorable outcome.", + "The total number of iterations to run per crafting step. " + + "Higher values require more computational power. Higher values " + + "also may decrease variance, so other values should be tweaked " + + "as necessary to get a more favorable outcome.", config.Iterations, 1000, 1000000, @@ -567,11 +652,11 @@ public sealed class Settings : Window, IDisposable DrawOption( "Max Iterations", - "The solver may go about the target iteration value if the craft " + - "is sufficiently difficult, and it wasn't able to find any way to " + - "complete it yet. In rare cases, the solver might go on for a very " + - "long time. This maximum is here to prevent the solver from stealing " + - "all your RAM.", + "The solver may go about the target iteration value if the craft " + + "is sufficiently difficult, and it wasn't able to find any way to " + + "complete it yet. In rare cases, the solver might go on for a very " + + "long time. This maximum is here to prevent the solver from stealing " + + "all your RAM.", config.MaxIterations, config.Iterations, 5000000, @@ -581,11 +666,11 @@ public sealed class Settings : Window, IDisposable DrawOption( "Max Step Count", - "The maximum number of crafting steps; this is generally the only " + - "setting you should change, and it should be set to around 5 steps " + - "more than what you'd expect. If this value is too low, the solver " + - "won't learn much per iteration; too high and it will waste time " + - "on useless extra steps.", + "The maximum number of crafting steps; this is generally the only " + + "setting you should change, and it should be set to around 5 steps " + + "more than what you'd expect. If this value is too low, the solver " + + "won't learn much per iteration; too high and it will waste time " + + "on useless extra steps.", config.MaxStepCount, 1, 100, @@ -595,9 +680,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Exploration Constant", - "A constant that decides how often the solver will explore new, " + - "possibly good paths. If this value is too high, " + - "moves will mostly be decided at random.", + "A constant that decides how often the solver will explore new, " + + "possibly good paths. If this value is too high, " + + "moves will mostly be decided at random.", config.ExplorationConstant, 0, 10, @@ -607,10 +692,10 @@ public sealed class Settings : Window, IDisposable DrawOption( "Score Weighting Constant", - "A constant ranging from 0 to 1 that configures how the solver " + - "scores and picks paths to travel to next. A value of 0 means " + - "actions will be chosen based on their average outcome, whereas " + - "1 uses their best outcome achieved so far.", + "A constant ranging from 0 to 1 that configures how the solver " + + "scores and picks paths to travel to next. A value of 0 means " + + "actions will be chosen based on their average outcome, whereas " + + "1 uses their best outcome achieved so far.", config.MaxScoreWeightingConstant, 0, 1, @@ -618,16 +703,25 @@ public sealed class Settings : Window, IDisposable ref isDirty ); - using (ImRaii.Disabled(config.Algorithm is not (SolverAlgorithm.OneshotForked or SolverAlgorithm.StepwiseForked or SolverAlgorithm.StepwiseGenetic))) + using ( + ImRaii.Disabled( + config.Algorithm + is not ( + SolverAlgorithm.OneshotForked + or SolverAlgorithm.StepwiseForked + or SolverAlgorithm.StepwiseGenetic + ) + ) + ) DrawOption( "Fork Count", - "Split the number of iterations across different solvers. In general, " + - "you should increase this value to at least the number of cores in " + - $"your system (FYI, you have {Environment.ProcessorCount} cores) to attain the most speedup. " + - "The higher the number, the more chance you have of finding a " + - "better local maximum; this concept similar but not equivalent " + - "to the exploration constant.\n" + - "(Only used in the Forked and Genetic algorithms)", + "Split the number of iterations across different solvers. In general, " + + "you should increase this value to at least the number of cores in " + + $"your system (FYI, you have {Environment.ProcessorCount} cores) to attain the most speedup. " + + "The higher the number, the more chance you have of finding a " + + "better local maximum; this concept similar but not equivalent " + + "to the exploration constant.\n" + + "(Only used in the Forked and Genetic algorithms)", config.ForkCount, 1, 500, @@ -638,10 +732,10 @@ public sealed class Settings : Window, IDisposable using (ImRaii.Disabled(config.Algorithm is not SolverAlgorithm.StepwiseGenetic)) DrawOption( "Elitist Action Count", - "On every craft step, pick this many top solutions and use them as " + - "the input for the next craft step. For best results, use Fork Count / 2 " + - "and add about 1 or 2 more if needed.\n" + - "(Only used in the Stepwise Genetic algorithm)", + "On every craft step, pick this many top solutions and use them as " + + "the input for the next craft step. For best results, use Fork Count / 2 " + + "and add about 1 or 2 more if needed.\n" + + "(Only used in the Stepwise Genetic algorithm)", config.FurcatedActionCount, 1, 500, @@ -653,16 +747,16 @@ public sealed class Settings : Window, IDisposable { DrawOption( "Backload Progress", - "Speeds up solve times. Backloads all Progress " + - "actions to the end of the rotation.", + "Speeds up solve times. Backloads all Progress " + + "actions to the end of the rotation.", config.BackloadProgress, v => config = config with { BackloadProgress = v }, ref isDirty ); DrawOption( "Ensure Reliability", - "Find a rotation that can reach the target quality no matter " + - "how unlucky the random conditions are.", + "Find a rotation that can reach the target quality no matter " + + "how unlucky the random conditions are.", config.Adversarial, v => config = config with { Adversarial = v }, ref isDirty @@ -677,7 +771,9 @@ public sealed class Settings : Window, IDisposable ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString()); } if (ImGui.IsItemHovered()) - ImGuiUtils.TooltipWrapped("\"Ensure Reliability\" uses a lot more memory and can significantly increase solve times."); + ImGuiUtils.TooltipWrapped( + "\"Ensure Reliability\" uses a lot more memory and can significantly increase solve times." + ); } } } @@ -703,9 +799,9 @@ public sealed class Settings : Window, IDisposable { DrawOption( "Max Rollout Step Count", - "The maximum number of crafting steps every iteration can consider. " + - "Decreasing this value can have unintended side effects. Only change " + - "this value if you absolutely know what you're doing.", + "The maximum number of crafting steps every iteration can consider. " + + "Decreasing this value can have unintended side effects. Only change " + + "this value if you absolutely know what you're doing.", config.MaxRolloutStepCount, 1, 50, @@ -715,9 +811,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Strict Actions", - "When finding the next possible actions to execute, use a heuristic " + - "to restrict which actions to attempt taking. This results in a much " + - "better macro at the cost of not finding an extremely creative one.", + "When finding the next possible actions to execute, use a heuristic " + + "to restrict which actions to attempt taking. This results in a much " + + "better macro at the cost of not finding an extremely creative one.", config.StrictActions, v => config = config with { StrictActions = v }, ref isDirty @@ -771,8 +867,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Steps", - "Amount of weight to give to the craft's number of steps. The lower " + - "the step count, the higher the score.", + "Amount of weight to give to the craft's number of steps. The lower " + + "the step count, the higher the score.", config.ScoreSteps, 0, 100, @@ -786,7 +882,11 @@ public sealed class Settings : Window, IDisposable configRef = config; } - private static void DrawActionPool(ref ActionType[] actionPool, float poolWidth, out bool isDirty) + private static void DrawActionPool( + ref ActionType[] actionPool, + float poolWidth, + out bool isDirty + ) { isDirty = false; @@ -799,14 +899,21 @@ public sealed class Settings : Window, IDisposable using var _color = ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero); using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero); using var _color2 = ImRaii.PushColor(ImGuiCol.ButtonActive, Vector4.Zero); - using var _alpha = ImRaii.PushStyle(ImGuiStyleVar.DisabledAlpha, ImGui.GetStyle().DisabledAlpha * .5f); + using var _alpha = ImRaii.PushStyle( + ImGuiStyleVar.DisabledAlpha, + ImGui.GetStyle().DisabledAlpha * .5f + ); foreach (var category in Enum.GetValues()) { if (category == ActionCategory.Combo) continue; var actions = category.GetActions(); - using var panel = ImRaii2.GroupPanel(category.GetDisplayName(), poolWidth, out var availSpace); + using var panel = ImRaii2.GroupPanel( + category.GetDisplayName(), + poolWidth, + out var availSpace + ); var itemsPerRow = (int)MathF.Floor((availSpace + spacing) / (imageSize + spacing)); var itemCount = actions.Count; var iterCount = (int)(Math.Ceiling((float)itemCount / itemsPerRow) * itemsPerRow); @@ -827,7 +934,17 @@ public sealed class Settings : Window, IDisposable iconTint = new(1, 1f, .5f, 1); else if (isRisky) iconTint = new(1, .5f, .5f, 1); - if (ImGui.ImageButton(actions[i].GetIcon(recipeData.ClassJob).Handle, new(imageSize), default, Vector2.One, 0, default, iconTint)) + if ( + ImGui.ImageButton( + actions[i].GetIcon(recipeData.ClassJob).Handle, + new(imageSize), + default, + Vector2.One, + 0, + default, + iconTint + ) + ) { isDirty = true; if (isEnabled) @@ -841,16 +958,18 @@ public sealed class Settings : Window, IDisposable s.AppendLine(actions[i].GetName(recipeData.ClassJob)); if (isInefficient) s.AppendLine( - "Not recommended. This action may be randomly used in a " + - "detrimental way to the rest of the craft. Always use " + - "your best judgement if enabling this action."); + "Not recommended. This action may be randomly used in a " + + "detrimental way to the rest of the craft. Always use " + + "your best judgement if enabling this action." + ); if (isRisky) s.AppendLine( - "Useless; the solver currently doesn't take any risks in " + - "its crafts. It only takes steps that have a 100% chance of " + - "succeeding. If you want have a moment where you want to take " + - "risks in your craft (like in expert recipes), don't rely " + - "on the solver during that time."); + "Useless; the solver currently doesn't take any risks in " + + "its crafts. It only takes steps that have a 100% chance of " + + "succeeding. If you want have a moment where you want to take " + + "risks in your craft (like in expert recipes), don't rely " + + "on the solver during that time." + ); ImGuiUtils.TooltipWrapped(s.ToString()); } } @@ -912,8 +1031,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Pin Helper Window", - "Pins the helper window to the right of your crafting log. Disabling this will " + - "allow you to move it around.", + "Pins the helper window to the right of your crafting log. Disabling this will " + + "allow you to move it around.", Config.PinRecipeNoteToWindow, v => Config.PinRecipeNoteToWindow = v, ref isDirty @@ -921,8 +1040,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Always Collapse Helper Window", - "Enabling this will cause the Helper Window to be collapsed whenever you start " + - "a new craft, preventing the solver from running automatically.", + "Enabling this will cause the Helper Window to be collapsed whenever you start " + + "a new craft, preventing the solver from running automatically.", Config.CollapseSynthHelper, v => Config.CollapseSynthHelper = v, ref isDirty @@ -930,11 +1049,11 @@ public sealed class Settings : Window, IDisposable DrawOption( "Automatically Suggest Macro", - "(Can cause frame drops!) When navigating to a new recipe or changing your gear " + - "stats, automatically suggest a new macro (equivalent to clicking \"Generate\" " + - "in the Macro Editor). This can cause harsh frame drops on some computers or " + - "recipes when underleveled while navigating the crafting log. Turning this off " + - "provides a button to allow you to manually suggest a macro only when you need it.", + "(Can cause frame drops!) When navigating to a new recipe or changing your gear " + + "stats, automatically suggest a new macro (equivalent to clicking \"Generate\" " + + "in the Macro Editor). This can cause harsh frame drops on some computers or " + + "recipes when underleveled while navigating the crafting log. Turning this off " + + "provides a button to allow you to manually suggest a macro only when you need it.", Config.SuggestMacroAutomatically, v => Config.SuggestMacroAutomatically = v, ref isDirty @@ -942,10 +1061,10 @@ public sealed class Settings : Window, IDisposable DrawOption( "Enable Community Macros", - "Use FFXIV Teamcraft's community rotations to search for and find the best possible " + - "crowd-sourced macro for your craft. This sends a request to their servers to retrieve " + - "a list of macros that apply to your craft's rlvl. Requests are only sent once per rlvl " + - "and are always cached to reduce server load.", + "Use FFXIV Teamcraft's community rotations to search for and find the best possible " + + "crowd-sourced macro for your craft. This sends a request to their servers to retrieve " + + "a list of macros that apply to your craft's rlvl. Requests are only sent once per rlvl " + + "and are always cached to reduce server load.", Config.ShowCommunityMacros, v => Config.ShowCommunityMacros = v, ref isDirty @@ -955,9 +1074,9 @@ public sealed class Settings : Window, IDisposable { DrawOption( "Automatically Search for Community Macro", - "When navigating to a new recipe or changing your gear stats, automatically search " + - "online for a new community macro.\n" + - "This is turned off by default so you don't hammer their servers :)", + "When navigating to a new recipe or changing your gear stats, automatically search " + + "online for a new community macro.\n" + + "This is turned off by default so you don't hammer their servers :)", Config.SearchCommunityMacroAutomatically, v => Config.SearchCommunityMacroAutomatically = v, ref isDirty @@ -969,7 +1088,12 @@ public sealed class Settings : Window, IDisposable ImGuiHelpers.ScaledDummy(5); var solverConfig = Config.RecipeNoteSolverConfig; - DrawSolverConfig(ref solverConfig, SolverConfig.RecipeNoteDefault, false, out var isSolverDirty); + DrawSolverConfig( + ref solverConfig, + SolverConfig.RecipeNoteDefault, + false, + out var isSolverDirty + ); if (isSolverDirty) { Config.RecipeNoteSolverConfig = solverConfig; @@ -991,7 +1115,12 @@ public sealed class Settings : Window, IDisposable var isDirty = false; var solverConfig = Config.EditorSolverConfig; - DrawSolverConfig(ref solverConfig, SolverConfig.EditorDefault, false, out var isSolverDirty); + DrawSolverConfig( + ref solverConfig, + SolverConfig.EditorDefault, + false, + out var isSolverDirty + ); if (isSolverDirty) { Config.EditorSolverConfig = solverConfig; @@ -1014,8 +1143,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Pin Helper Window", - "Pins the synthesis helper to the right of your synthesis window. Disabling this will " + - "allow you to move it around.", + "Pins the synthesis helper to the right of your synthesis window. Disabling this will " + + "allow you to move it around.", Config.PinSynthHelperToWindow, v => Config.PinSynthHelperToWindow = v, ref isDirty @@ -1031,9 +1160,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Simulate Only First Step", - "Only the first step is simulated by default. You can still " + - "hover over the other steps to view their outcomes, but the " + - "reliability trials (when hovering over the macro stats) are hidden.", + "Only the first step is simulated by default. You can still " + + "hover over the other steps to view their outcomes, but the " + + "reliability trials (when hovering over the macro stats) are hidden.", Config.SynthHelperDisplayOnlyFirstStep, v => Config.SynthHelperDisplayOnlyFirstStep = v, ref isDirty @@ -1041,9 +1170,9 @@ public sealed class Settings : Window, IDisposable DrawOption( "Draw Ability Ants", - "Turns your hotbar into a whack-a-mole game! Draws ants for " + - "the next action that should be executed. Also disables ants " + - "for things like combo actions and condition procs.", + "Turns your hotbar into a whack-a-mole game! Draws ants for " + + "the next action that should be executed. Also disables ants " + + "for things like combo actions and condition procs.", Config.SynthHelperAbilityAnts, v => Config.SynthHelperAbilityAnts = v, ref isDirty @@ -1051,8 +1180,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Solver Step Count", - "The minimum number of future steps to solve for during an in-game craft. " + - "The solver may still give more than this amount if it's at no cost to you.", + "The minimum number of future steps to solve for during an in-game craft. " + + "The solver may still give more than this amount if it's at no cost to you.", Config.SynthHelperStepCount, 1, 100, @@ -1062,8 +1191,8 @@ public sealed class Settings : Window, IDisposable DrawOption( "Max Step Display Count", - "Enforces a maximum number of steps to display in the synth helper to " + - "get rid of clutter.", + "Enforces a maximum number of steps to display in the synth helper to " + + "get rid of clutter.", Config.SynthHelperMaxDisplayCount, Config.SynthHelperStepCount, 100, @@ -1076,7 +1205,12 @@ public sealed class Settings : Window, IDisposable ImGuiHelpers.ScaledDummy(5); var solverConfig = Config.SynthHelperSolverConfig; - DrawSolverConfig(ref solverConfig, SolverConfig.SynthHelperDefault, true, out var isSolverDirty); + DrawSolverConfig( + ref solverConfig, + SolverConfig.SynthHelperDefault, + true, + out var isSolverDirty + ); if (isSolverDirty) { Config.SynthHelperSolverConfig = solverConfig; @@ -1109,18 +1243,33 @@ public sealed class Settings : Window, IDisposable ImGui.Image(icon.Handle, iconDim); ImGui.TableNextColumn(); - ImGuiUtils.AlignMiddle(new(float.PositiveInfinity, HeaderFont.GetFontSize() + SubheaderFont.GetFontSize() + ImGui.GetFontSize() * 3 + ImGui.GetStyle().ItemSpacing.Y * 4), new(0, iconDim.Y)); + ImGuiUtils.AlignMiddle( + new( + float.PositiveInfinity, + HeaderFont.GetFontSize() + + SubheaderFont.GetFontSize() + + ImGui.GetFontSize() * 3 + + ImGui.GetStyle().ItemSpacing.Y * 4 + ), + new(0, iconDim.Y) + ); using (HeaderFont.Push()) { ImGuiUtils.AlignCentered(ImGui.CalcTextSize("Forgeimizer").X); - ImGuiUtils.Hyperlink("Forgeimizer", "https://gitea.hellion-forge.cloud/JonKazama-Hellion/Craftimizer", false); + ImGuiUtils.Hyperlink( + "Forgeimizer", + "https://gitea.hellion-forge.cloud/JonKazama-Hellion/Craftimizer", + false + ); } using (SubheaderFont.Push()) ImGuiUtils.TextCentered($"v{plugin.Version} {plugin.BuildConfiguration}"); - ImGuiUtils.AlignCentered(ImGui.CalcTextSize($"By {plugin.Author} (WorkingRobot)").X); + ImGuiUtils.AlignCentered( + ImGui.CalcTextSize($"By {plugin.Author} (WorkingRobot)").X + ); ImGui.TextUnformatted($"By {plugin.Author} ("); ImGui.SameLine(0, 0); ImGuiUtils.Hyperlink("WorkingRobot", "https://github.com/WorkingRobot"); @@ -1178,11 +1327,17 @@ public sealed class Settings : Window, IDisposable ImGuiUtils.TextWrappedTo("Thank you to "); ImGui.SameLine(0, 0); - ImGuiUtils.Hyperlink("this", "https://dke.maastrichtuniversity.nl/m.winands/documents/multithreadedMCTS2.pdf"); + ImGuiUtils.Hyperlink( + "this", + "https://dke.maastrichtuniversity.nl/m.winands/documents/multithreadedMCTS2.pdf" + ); ImGui.SameLine(0, 0); ImGuiUtils.TextWrappedTo(", "); ImGui.SameLine(0, 0); - ImGuiUtils.Hyperlink("this", "https://liacs.leidenuniv.nl/~plaata1/papers/paper_ICAART18.pdf"); + ImGuiUtils.Hyperlink( + "this", + "https://liacs.leidenuniv.nl/~plaata1/papers/paper_ICAART18.pdf" + ); ImGui.SameLine(0, 0); ImGuiUtils.TextWrappedTo(", and "); ImGui.SameLine(0, 0); diff --git a/Craftimizer/Windows/SynthHelper.cs b/Craftimizer/Windows/SynthHelper.cs index 5036fe6..4d414e1 100644 --- a/Craftimizer/Windows/SynthHelper.cs +++ b/Craftimizer/Windows/SynthHelper.cs @@ -1,7 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Threading; using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using Craftimizer.Utils; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Conditions; using Dalamud.Interface; using Dalamud.Interface.Colors; @@ -15,12 +21,6 @@ using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI.Shell; -using Dalamud.Bindings.ImGui; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Threading; using ActionType = Craftimizer.Simulator.Actions.ActionType; using Sim = Craftimizer.Simulator.Simulator; using SimNoRandom = Craftimizer.Simulator.SimulatorNoRandom; @@ -29,12 +29,11 @@ namespace Craftimizer.Windows; public sealed unsafe class SynthHelper : Window, IDisposable { - private const ImGuiWindowFlags WindowFlagsPinned = WindowFlagsFloating - | ImGuiWindowFlags.NoSavedSettings; + private const ImGuiWindowFlags WindowFlagsPinned = + WindowFlagsFloating | ImGuiWindowFlags.NoSavedSettings; private const ImGuiWindowFlags WindowFlagsFloating = - ImGuiWindowFlags.AlwaysAutoResize - | ImGuiWindowFlags.NoFocusOnAppearing; + ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoFocusOnAppearing; private const string WindowNamePinned = "Craftimizer Synthesis Helper###CraftimizerSynthHelper"; private const string WindowNameFloating = $"{WindowNamePinned}Floating"; @@ -69,9 +68,12 @@ public sealed unsafe class SynthHelper : Window, IDisposable private IFontHandle AxisFont { get; } - public SynthHelper() : base(WindowNamePinned) + public SynthHelper() + : base(WindowNamePinned) { - AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis14)); + AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle( + new(GameFontFamilyAndSize.Axis14) + ); Service.Plugin.Hooks.OnActionUsed += OnUseAction; @@ -83,7 +85,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable SizeConstraints = new WindowSizeConstraints { MinimumSize = new(494, -1), - MaximumSize = new(494, 10000) + MaximumSize = new(494, 10000), }; TitleBarButtons = @@ -93,14 +95,15 @@ public sealed unsafe class SynthHelper : Window, IDisposable Icon = FontAwesomeIcon.Cog, IconOffset = new(2, 1), Click = _ => Service.Plugin.OpenSettingsTab("Synthesis Helper"), - ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings") + ShowTooltip = () => ImGuiUtils.Tooltip("Open Settings"), }, - new() { + new() + { Icon = FontAwesomeIcon.Heart, IconOffset = new(2, 1), Click = _ => Util.OpenLink(Plugin.Plugin.SupportLink), - ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!") - } + ShowTooltip = () => ImGuiUtils.Tooltip("Support me on Ko-fi!"), + }, ]; Service.WindowSystem.AddWindow(this); @@ -153,10 +156,10 @@ public sealed unsafe class SynthHelper : Window, IDisposable WasCalculatable = ShouldCalculate; } - public override bool DrawConditions() => - ShouldOpen; + public override bool DrawConditions() => ShouldOpen; private bool wasInCraftAction; + private bool CalculateShouldOpen() { if (Service.Objects.LocalPlayer == null) @@ -209,7 +212,8 @@ public sealed unsafe class SynthHelper : Window, IDisposable OnStartCrafting(recipeId); OnStateUpdated(); - if (Service.Configuration.CollapseSynthHelper) ShouldCollapse = true; + if (Service.Configuration.CollapseSynthHelper) + ShouldCollapse = true; } if (IsRecalculateQueued) @@ -228,6 +232,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable private Vector2? LastPosition { get; set; } private byte? StyleAlpha { get; set; } private byte? LastAlpha { get; set; } + public override void PreDraw() { base.PreDraw(); @@ -239,7 +244,9 @@ public sealed unsafe class SynthHelper : Window, IDisposable ref var unit = ref Addon->AtkUnitBase; var scale = unit.Scale; var pos = new Vector2(unit.X, unit.Y); - var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale; + var size = + new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) + * scale; var offset = 5; @@ -261,7 +268,10 @@ public sealed unsafe class SynthHelper : Window, IDisposable WindowName = WindowNameFloating; } - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, StyleAlpha.HasValue ? (StyleAlpha.Value / 255f) : 1); + ImGui.PushStyleVar( + ImGuiStyleVar.Alpha, + StyleAlpha.HasValue ? (StyleAlpha.Value / 255f) : 1 + ); } public override void PostDraw() @@ -273,7 +283,6 @@ public sealed unsafe class SynthHelper : Window, IDisposable public override void Draw() { - if (ShouldCollapse) { ImGui.SetWindowCollapsed(true); @@ -298,7 +307,9 @@ public sealed unsafe class SynthHelper : Window, IDisposable } private SimulationState? hoveredState; - private SimulationState DisplayedState => hoveredState ?? (Service.Configuration.SynthHelperDisplayOnlyFirstStep ? Macro.FirstState : Macro.State); + private SimulationState DisplayedState => + hoveredState + ?? (Service.Configuration.SynthHelperDisplayOnlyFirstStep ? Macro.FirstState : Macro.State); private void DrawMacro() { @@ -308,7 +319,11 @@ public sealed unsafe class SynthHelper : Window, IDisposable var lastState = Macro.InitialState; hoveredState = null; - var itemsPerRow = (int)Math.Max(1, MathF.Floor((ImGui.GetContentRegionAvail().X + spacing) / (imageSize + spacing))); + var itemsPerRow = (int) + Math.Max( + 1, + MathF.Floor((ImGui.GetContentRegionAvail().X + spacing) / (imageSize + spacing)) + ); using var _color = ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero); using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero); @@ -328,9 +343,18 @@ public sealed unsafe class SynthHelper : Window, IDisposable var offsetVec2 = ImGui.GetStyle().ItemSpacing / 2; var offset = new Vector2((offsetVec2.X + offsetVec2.Y) / 2f); var color = canExecute ? ImGuiColors.DalamudWhite2 : ImGuiColors.DalamudGrey3; - ImGui.GetWindowDrawList().AddRectFilled(pos - offset, pos + new Vector2(imageSize) + offset, ImGui.GetColorU32(color), 4); + ImGui + .GetWindowDrawList() + .AddRectFilled( + pos - offset, + pos + new Vector2(imageSize) + offset, + ImGui.GetColorU32(color), + 4 + ); } - bool isHovered, isHeld, isPressed; + bool isHovered, + isHeld, + isPressed; { var pos = ImGui.GetCursorScreenPos(); var offset = ImGui.GetStyle().ItemSpacing / 2f; @@ -344,9 +368,23 @@ public sealed unsafe class SynthHelper : Window, IDisposable var id = ImGui.GetID($"###ButtonContainer"); var isClipped = !ImGuiExtras.ItemAdd(bb, id, out _, 0); - isPressed = ImGuiExtras.ButtonBehavior(bb, id, out isHovered, out isHeld, ImGuiButtonFlags.None); + isPressed = ImGuiExtras.ButtonBehavior( + bb, + id, + out isHovered, + out isHeld, + ImGuiButtonFlags.None + ); } - ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).Handle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One); + ImGui.ImageButton( + action.GetIcon(RecipeData!.ClassJob).Handle, + new(imageSize), + default, + Vector2.One, + 0, + default, + failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One + ); if (isPressed && i == 0) { if (ExecuteNextAction()) @@ -354,15 +392,21 @@ public sealed unsafe class SynthHelper : Window, IDisposable } if (isHovered) { - ImGuiUtils.Tooltip($"{action.GetName(RecipeData!.ClassJob)}\n" + - $"{actionBase.GetTooltip(CreateSim(lastState), true)}" + - $"{(canExecute && i == 0 ? "Click or run /craftaction to execute" : string.Empty)}"); + ImGuiUtils.Tooltip( + $"{action.GetName(RecipeData!.ClassJob)}\n" + + $"{actionBase.GetTooltip(CreateSim(lastState), true)}" + + $"{(canExecute && i == 0 ? "Click or run /craftaction to execute" : string.Empty)}" + ); hoveredState = state; } lastState = state; } - var rows = (int)Math.Max(1, MathF.Ceiling(Service.Configuration.SynthHelperMaxDisplayCount / itemsPerRow)); + var rows = (int) + Math.Max( + 1, + MathF.Ceiling(Service.Configuration.SynthHelperMaxDisplayCount / itemsPerRow) + ); for (var i = 0; i < rows; ++i) { if (count <= i * itemsPerRow) @@ -381,7 +425,15 @@ public sealed unsafe class SynthHelper : Window, IDisposable var iconHeight = ImGui.GetFrameHeight() * 1.75f; var durationShift = iconHeight * .2f; - ImGui.Dummy(new(0, iconHeight + ImGui.GetStyle().ItemSpacing.Y + ImGui.GetTextLineHeight() - durationShift)); + ImGui.Dummy( + new( + 0, + iconHeight + + ImGui.GetStyle().ItemSpacing.Y + + ImGui.GetTextLineHeight() + - durationShift + ) + ); ImGui.SameLine(0, 0); var effects = state.ActiveEffects; @@ -413,35 +465,92 @@ public sealed unsafe class SynthHelper : Window, IDisposable } } - var reliability = Macro.GetReliability(RecipeData!, Service.Configuration.SynthHelperDisplayOnlyFirstStep ? 0 : ^1); + var reliability = Macro.GetReliability( + RecipeData!, + Service.Configuration.SynthHelperDisplayOnlyFirstStep ? 0 : ^1 + ); { var mainBars = new List() { - new("Progress", Colors.Progress, reliability.Progress, state.Progress, RecipeData!.RecipeInfo.MaxProgress), - new("Quality", Colors.Quality, reliability.Quality, state.Quality, RecipeData.RecipeInfo.MaxQuality), + new( + "Progress", + Colors.Progress, + reliability.Progress, + state.Progress, + RecipeData!.RecipeInfo.MaxProgress + ), + new( + "Quality", + Colors.Quality, + reliability.Quality, + state.Quality, + RecipeData.RecipeInfo.MaxQuality + ), new("CP", Colors.CP, state.CP, CharacterStats!.CP), }; if (RecipeData.RecipeInfo.MaxQuality <= 0) mainBars.RemoveAt(1); var halfBars = new List() { - new("Durability", Colors.Durability, state.Durability, RecipeData.RecipeInfo.MaxDurability), + new( + "Durability", + Colors.Durability, + state.Durability, + RecipeData.RecipeInfo.MaxDurability + ), }; if (RecipeData.IsCollectable) - halfBars.Add(new("Collectability", Colors.Collectability, reliability.ParamScore, state.Collectability, state.MaxCollectability, RecipeData.CollectableThresholds, $"{state.Collectability}", $"{state.MaxCollectability:0}")); + halfBars.Add( + new( + "Collectability", + Colors.Collectability, + reliability.ParamScore, + state.Collectability, + state.MaxCollectability, + RecipeData.CollectableThresholds, + $"{state.Collectability}", + $"{state.MaxCollectability:0}" + ) + ); else if (RecipeData.Recipe.RequiredQuality > 0) { var qualityPercent = (float)state.Quality / RecipeData.Recipe.RequiredQuality * 100; - halfBars.Add(new("Quality %", Colors.HQ, reliability.ParamScore, qualityPercent, 100, null, $"{qualityPercent:0}%", null)); + halfBars.Add( + new( + "Quality %", + Colors.HQ, + reliability.ParamScore, + qualityPercent, + 100, + null, + $"{qualityPercent:0}%", + null + ) + ); } else if (RecipeData.RecipeInfo.MaxQuality > 0) - halfBars.Add(new("HQ %", Colors.HQ, reliability.ParamScore, state.HQPercent, 100, null, $"{state.HQPercent}%", null)); + halfBars.Add( + new( + "HQ %", + Colors.HQ, + reliability.ParamScore, + state.HQPercent, + 100, + null, + $"{state.HQPercent}%", + null + ) + ); if (halfBars.Count > 1) { var textSize = DynamicBars.GetTextSize(mainBars.Concat(halfBars)); DynamicBars.Draw(mainBars, textSize); - using var table = ImRaii.Table($"##{nameof(SynthHelper)}_halfbars", halfBars.Count, ImGuiTableFlags.NoPadOuterX | ImGuiTableFlags.SizingStretchSame); + using var table = ImRaii.Table( + $"##{nameof(SynthHelper)}_halfbars", + halfBars.Count, + ImGuiTableFlags.NoPadOuterX | ImGuiTableFlags.SizingStretchSame + ); if (table) { foreach (var bar in halfBars) @@ -467,7 +576,9 @@ public sealed unsafe class SynthHelper : Window, IDisposable using var _disabled = ImRaii.Disabled(); ImGui.Button("Stopping", new(-1, 0)); if (ImGui.IsItemHovered()) - ImGuiUtils.TooltipWrapped("This might could a while, sorry! Please report if this takes longer than a second."); + ImGuiUtils.TooltipWrapped( + "This might could a while, sorry! Please report if this takes longer than a second." + ); } else { @@ -480,13 +591,22 @@ public sealed unsafe class SynthHelper : Window, IDisposable if (ImGui.Button("Retry", new(-1, 0))) AttemptRetry(); if (ImGui.IsItemHovered()) - ImGuiUtils.TooltipWrapped("Suggest a way to finish the crafting recipe. " + - "Results aren't perfect, and levels of success " + - "can vary wildly depending on the solver's settings."); + ImGuiUtils.TooltipWrapped( + "Suggest a way to finish the crafting recipe. " + + "Results aren't perfect, and levels of success " + + "can vary wildly depending on the solver's settings." + ); } if (ImGui.Button("Open in Macro Editor", new(-1, 0))) - Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), null, [], null); + Service.Plugin.OpenMacroEditor( + CharacterStats!, + RecipeData!, + new(Service.Objects.LocalPlayer!.StatusList), + null, + [], + null + ); } public bool ExecuteNextAction() @@ -519,13 +639,20 @@ public sealed unsafe class SynthHelper : Window, IDisposable { var gearStats = Gearsets.CalculateGearsetCurrentStats(); - var container = InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems); + var container = InventoryManager + .Instance() + ->GetInventoryContainer(InventoryType.EquippedItems); if (container == null) throw new InvalidOperationException("Could not get inventory container"); var gearItems = Gearsets.GetGearsetItems(container); - var characterStats = Gearsets.CalculateCharacterStats(gearStats, gearItems, RecipeData.ClassJob.GetPlayerLevel(), RecipeData.ClassJob.CanPlayerUseManipulation()); + var characterStats = Gearsets.CalculateCharacterStats( + gearStats, + gearItems, + RecipeData.ClassJob.GetPlayerLevel(), + RecipeData.ClassJob.CanPlayerUseManipulation() + ); if (characterStats != CharacterStats) { CharacterStats = characterStats; @@ -554,8 +681,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable CurrentActionStates = CurrentState.ActionStates; } - private void RefreshCurrentState() => - CurrentState = GetCurrentState(); + private void RefreshCurrentState() => CurrentState = GetCurrentState(); private SimulationState GetCurrentState() { @@ -602,7 +728,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable TrainedPerfection = HasEffect((ushort)EffectType.TrainedPerfection.StatusId()), HeartAndSoul = HasEffect((ushort)EffectType.HeartAndSoul.StatusId()), }, - ActionStates = CurrentActionStates + ActionStates = CurrentActionStates, }; } @@ -638,7 +764,11 @@ public sealed unsafe class SynthHelper : Window, IDisposable SolverTask.Start(); } - private int CalculateBestMacroTask(SimulationState state, CancellationToken token, bool hasDelineations) + private int CalculateBestMacroTask( + SimulationState state, + CancellationToken token, + bool hasDelineations + ) { var config = Service.Configuration.SynthHelperSolverConfig; var canUseDelineations = !Service.Configuration.CheckDelineations || hasDelineations; @@ -663,12 +793,17 @@ public sealed unsafe class SynthHelper : Window, IDisposable private void EnqueueAction(ActionType action) { var newSize = Macro.Enqueue(action, Service.Configuration.SynthHelperMaxDisplayCount); - if (newSize >= Service.Configuration.SynthHelperStepCount || newSize >= Service.Configuration.SynthHelperMaxDisplayCount) + if ( + newSize >= Service.Configuration.SynthHelperStepCount + || newSize >= Service.Configuration.SynthHelperMaxDisplayCount + ) SolverTask?.Cancel(); } private static Sim CreateSim(in SimulationState state) => - Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state }; + Service.Configuration.ConditionRandomness + ? new Sim() { State = state } + : new SimNoRandom() { State = state }; public void Dispose() {