From 895e2a44607ff277786c3206f83990419f68c9e5 Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Fri, 22 Mar 2024 23:59:00 -0700 Subject: [PATCH] Refactor and move around config/settings window --- Craftimizer/Configuration.cs | 7 +- Craftimizer/Windows/MacroEditor.cs | 2 +- Craftimizer/Windows/MacroList.cs | 2 +- Craftimizer/Windows/RecipeNote.cs | 10 +-- Craftimizer/Windows/Settings.cs | 133 +++++++++++++++++------------ Craftimizer/Windows/SynthHelper.cs | 2 +- Solver/SolverConfig.cs | 130 ++++++++++++++++++++-------- 7 files changed, 189 insertions(+), 97 deletions(-) diff --git a/Craftimizer/Configuration.cs b/Craftimizer/Configuration.cs index ed8605a..2add81a 100644 --- a/Craftimizer/Configuration.cs +++ b/Craftimizer/Configuration.cs @@ -85,10 +85,15 @@ public class Configuration : IPluginConfiguration public IReadOnlyList Macros => macros; public int ReliabilitySimulationCount { get; set; } = 500; public bool ConditionRandomness { get; set; } = true; + [JsonConverter(typeof(PopulateConverter))] - public SolverConfig SimulatorSolverConfig { get; set; } = SolverConfig.SimulatorDefault; + [JsonProperty(PropertyName = "SimulatorSolverConfig")] + public SolverConfig RecipeNoteSolverConfig { get; set; } = SolverConfig.RecipeNoteDefault; + [JsonConverter(typeof(PopulateConverter))] + public SolverConfig EditorSolverConfig { get; set; } = SolverConfig.EditorDefault; [JsonConverter(typeof(PopulateConverter))] public SolverConfig SynthHelperSolverConfig { get; set; } = SolverConfig.SynthHelperDefault; + public bool EnableSynthHelper { get; set; } = true; public bool DisableSynthHelperOnMacro { get; set; } = true; public bool ShowOptimalMacroStat { get; set; } = true; diff --git a/Craftimizer/Windows/MacroEditor.cs b/Craftimizer/Windows/MacroEditor.cs index ca75d69..2cfef5b 100644 --- a/Craftimizer/Windows/MacroEditor.cs +++ b/Craftimizer/Windows/MacroEditor.cs @@ -1603,7 +1603,7 @@ public sealed class MacroEditor : Window, IDisposable private void CalculateBestMacroTask(SimulationState state, CancellationToken token) { - var config = Service.Configuration.SimulatorSolverConfig; + var config = Service.Configuration.EditorSolverConfig; token.ThrowIfCancellationRequested(); diff --git a/Craftimizer/Windows/MacroList.cs b/Craftimizer/Windows/MacroList.cs index 2d57431..225c9cd 100644 --- a/Craftimizer/Windows/MacroList.cs +++ b/Craftimizer/Windows/MacroList.cs @@ -239,7 +239,7 @@ public sealed class MacroList : Window, IDisposable if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) OpenEditor(macro); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip("Open in Simulator"); + ImGuiUtils.Tooltip("Open in Macro Editor"); ImGui.SameLine(0, spacing); if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.PencilAlt, miniRowHeight)) ShowRenamePopup(macro); diff --git a/Craftimizer/Windows/RecipeNote.cs b/Craftimizer/Windows/RecipeNote.cs index b78bdb0..ee94768 100644 --- a/Craftimizer/Windows/RecipeNote.cs +++ b/Craftimizer/Windows/RecipeNote.cs @@ -400,7 +400,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (ImGui.Button("View Saved Macros", new(availWidth, 0))) Service.Plugin.OpenMacroListWindow(); - if (ImGui.Button("Open in Simulator", new(availWidth, 0))) + if (ImGui.Button("Open in Macro Editor", new(availWidth, 0))) Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), Enumerable.Empty(), null); } @@ -932,7 +932,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), actions, state.MacroEditorSetter); if (ImGui.IsItemHovered()) - ImGuiUtils.Tooltip("Open in Simulator"); + ImGuiUtils.Tooltip("Open in Macro Editor"); if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight)) Service.Plugin.CopyMacro(actions); if (ImGui.IsItemHovered()) @@ -1085,7 +1085,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var state = new SimulationState(input); - var config = Service.Configuration.SimulatorSolverConfig; + var config = Service.Configuration.RecipeNoteSolverConfig; var mctsConfig = new MCTSConfig(config); var simulator = new SimulatorNoRandom(); List macros = new(Service.Configuration.Macros); @@ -1116,7 +1116,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var state = new SimulationState(input); - var config = Service.Configuration.SimulatorSolverConfig; + var config = Service.Configuration.RecipeNoteSolverConfig; token.ThrowIfCancellationRequested(); @@ -1140,7 +1140,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var state = new SimulationState(input); - var config = Service.Configuration.SimulatorSolverConfig; + var config = Service.Configuration.RecipeNoteSolverConfig; var mctsConfig = new MCTSConfig(config); var simulator = new SimulatorNoRandom(); var macros = Service.CommunityMacros.RetrieveRotations(input.Recipe.RLvl, token).GetAwaiter().GetResult(); diff --git a/Craftimizer/Windows/Settings.cs b/Craftimizer/Windows/Settings.cs index 046bbf2..0e110dd 100644 --- a/Craftimizer/Windows/Settings.cs +++ b/Craftimizer/Windows/Settings.cs @@ -165,7 +165,8 @@ public sealed class Settings : Window, IDisposable if (ImGui.BeginTabBar("settingsTabBar")) { DrawTabGeneral(); - DrawTabSimulator(); + DrawTabRecipeNote(); + DrawTabMacroEditor(); if (Config.EnableSynthHelper) DrawTabSynthHelper(); DrawTabAbout(); @@ -194,51 +195,6 @@ public sealed class Settings : Window, IDisposable ref isDirty ); - DrawOption( - "Pin Crafting Log Window", - "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 - ); - - DrawOption( - "Automatically Suggest Macro in Crafting Log", - "(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 - ); - - DrawOption( - "Enable Community Macros in Crafting Log", - "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 - ); - - if (Config.ShowCommunityMacros) - { - 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 :)", - Config.SearchCommunityMacroAutomatically, - v => Config.SearchCommunityMacroAutomatically = v, - ref isDirty - ); - } - 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 " + @@ -470,7 +426,7 @@ public sealed class Settings : Window, IDisposable "as necessary to get a more favorable outcome.", config.Iterations, 1000, - 500000, + 1000000, v => config = config with { Iterations = v }, ref isDirty ); @@ -809,9 +765,9 @@ public sealed class Settings : Window, IDisposable } } - private void DrawTabSimulator() + private void DrawTabRecipeNote() { - using var tab = TabItem("Simulator"); + using var tab = TabItem("Crafting Log"); if (!tab) return; @@ -819,11 +775,82 @@ public sealed class Settings : Window, IDisposable var isDirty = false; - var solverConfig = Config.SimulatorSolverConfig; - DrawSolverConfig(ref solverConfig, SolverConfig.SimulatorDefault, out var isSolverDirty); + DrawOption( + "Pin Helper Window", + "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 + ); + + 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.", + Config.SuggestMacroAutomatically, + v => Config.SuggestMacroAutomatically = v, + ref isDirty + ); + + 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.", + Config.ShowCommunityMacros, + v => Config.ShowCommunityMacros = v, + ref isDirty + ); + + if (Config.ShowCommunityMacros) + { + 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 :)", + Config.SearchCommunityMacroAutomatically, + v => Config.SearchCommunityMacroAutomatically = v, + ref isDirty + ); + } + + ImGuiHelpers.ScaledDummy(5); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(5); + + var solverConfig = Config.RecipeNoteSolverConfig; + DrawSolverConfig(ref solverConfig, SolverConfig.RecipeNoteDefault, out var isSolverDirty); if (isSolverDirty) { - Config.SimulatorSolverConfig = solverConfig; + Config.RecipeNoteSolverConfig = solverConfig; + isDirty = true; + } + + if (isDirty) + Config.Save(); + } + + private void DrawTabMacroEditor() + { + using var tab = TabItem("Macro Editor"); + if (!tab) + return; + + ImGuiHelpers.ScaledDummy(5); + + var isDirty = false; + + var solverConfig = Config.EditorSolverConfig; + DrawSolverConfig(ref solverConfig, SolverConfig.EditorDefault, out var isSolverDirty); + if (isSolverDirty) + { + Config.EditorSolverConfig = solverConfig; isDirty = true; } @@ -842,7 +869,7 @@ public sealed class Settings : Window, IDisposable var isDirty = false; DrawOption( - "Pin Window", + "Pin Helper Window", "Pins the synthesis helper to the right of your synthesis window. Disabling this will " + "allow you to move it around.", Config.PinSynthHelperToWindow, diff --git a/Craftimizer/Windows/SynthHelper.cs b/Craftimizer/Windows/SynthHelper.cs index 754813a..d1853c8 100644 --- a/Craftimizer/Windows/SynthHelper.cs +++ b/Craftimizer/Windows/SynthHelper.cs @@ -426,7 +426,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable "can vary wildly depending on the solver's settings."); } - if (ImGui.Button("Open in Simulator", new(-1, 0))) + if (ImGui.Button("Open in Macro Editor", new(-1, 0))) Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), Enumerable.Empty(), null); } diff --git a/Solver/SolverConfig.cs b/Solver/SolverConfig.cs index 4522c50..8241ea8 100644 --- a/Solver/SolverConfig.cs +++ b/Solver/SolverConfig.cs @@ -1,4 +1,5 @@ using Craftimizer.Simulator.Actions; +using System.Collections.Frozen; using System.Runtime.InteropServices; namespace Craftimizer.Solver; @@ -37,7 +38,7 @@ public readonly record struct SolverConfig public SolverConfig() { - Iterations = 100000; + Iterations = 100_000; ScoreStorageThreshold = 1f; MaxScoreWeightingConstant = 0.1f; ExplorationConstant = 4; @@ -56,63 +57,122 @@ public readonly record struct SolverConfig ScoreCP = .05f; ScoreSteps = .05f; - ActionPool = DefaultActionPool; + ActionPool = DeterministicActionPool; Algorithm = SolverAlgorithm.StepwiseFurcated; } public static ActionType[] OptimizeActionPool(IEnumerable actions) => actions.Order().ToArray(); - public static readonly ActionType[] DefaultActionPool = OptimizeActionPool(new[] + public static readonly ActionType[] DeterministicActionPool = OptimizeActionPool(new[] { + ActionType.MuscleMemory, + ActionType.Reflect, + ActionType.TrainedEye, + + ActionType.BasicSynthesis, + ActionType.CarefulSynthesis, + ActionType.FocusedSynthesis, + ActionType.Groundwork, + ActionType.DelicateSynthesis, + ActionType.PrudentSynthesis, + + ActionType.BasicTouch, + ActionType.StandardTouch, + ActionType.ByregotsBlessing, + ActionType.PrudentTouch, + ActionType.FocusedTouch, + ActionType.PreparatoryTouch, + ActionType.AdvancedTouch, + ActionType.TrainedFinesse, + + ActionType.MastersMend, + ActionType.WasteNot, + ActionType.WasteNot2, + ActionType.Manipulation, + + ActionType.Veneration, + ActionType.GreatStrides, + ActionType.Innovation, + + ActionType.Observe, + ActionType.StandardTouchCombo, ActionType.AdvancedTouchCombo, ActionType.FocusedTouchCombo, ActionType.FocusedSynthesisCombo, - ActionType.TrainedFinesse, - ActionType.PrudentSynthesis, - ActionType.Groundwork, - ActionType.AdvancedTouch, - ActionType.CarefulSynthesis, - ActionType.TrainedEye, - ActionType.DelicateSynthesis, - ActionType.PreparatoryTouch, - ActionType.Reflect, - ActionType.PrudentTouch, - ActionType.Manipulation, + }); + + // Same as deterministic, but with condition-specific actions added + public static readonly ActionType[] RandomizedActionPool = OptimizeActionPool(new[] + { ActionType.MuscleMemory, - ActionType.ByregotsBlessing, - ActionType.WasteNot2, + ActionType.Reflect, + ActionType.TrainedEye, + ActionType.BasicSynthesis, - ActionType.Innovation, - ActionType.GreatStrides, - ActionType.StandardTouch, - ActionType.Veneration, - ActionType.WasteNot, - ActionType.MastersMend, + ActionType.CarefulSynthesis, + ActionType.FocusedSynthesis, + ActionType.Groundwork, + ActionType.DelicateSynthesis, + ActionType.IntensiveSynthesis, + ActionType.PrudentSynthesis, + ActionType.BasicTouch, + ActionType.StandardTouch, + ActionType.ByregotsBlessing, + ActionType.PreciseTouch, + ActionType.PrudentTouch, + ActionType.FocusedTouch, + ActionType.PreparatoryTouch, + ActionType.AdvancedTouch, + ActionType.TrainedFinesse, + + ActionType.MastersMend, + ActionType.WasteNot, + ActionType.WasteNot2, + ActionType.Manipulation, + + ActionType.Veneration, + ActionType.GreatStrides, + ActionType.Innovation, + + ActionType.Observe, + ActionType.TricksOfTheTrade, + + ActionType.StandardTouchCombo, + ActionType.AdvancedTouchCombo, + ActionType.FocusedTouchCombo, + ActionType.FocusedSynthesisCombo, }); - public static readonly IReadOnlySet InefficientActions = new HashSet(new[] - { - ActionType.CarefulObservation, - ActionType.HeartAndSoul, - ActionType.FinalAppraisal - }); + public static readonly FrozenSet InefficientActions = + new[] + { + ActionType.CarefulObservation, + ActionType.HeartAndSoul, + ActionType.FinalAppraisal + }.ToFrozenSet(); - public static readonly IReadOnlySet RiskyActions = new HashSet(new[] - { - ActionType.RapidSynthesis, - ActionType.HastyTouch, - }); + public static readonly FrozenSet RiskyActions = + new[] + { + ActionType.RapidSynthesis, + ActionType.HastyTouch, + }.ToFrozenSet(); - public static readonly SolverConfig SimulatorDefault = new SolverConfig() with + public static readonly SolverConfig RecipeNoteDefault = new SolverConfig() with { }; + public static readonly SolverConfig EditorDefault = new SolverConfig() with + { + Iterations = 500000 + }; + public static readonly SolverConfig SynthHelperDefault = new SolverConfig() with { - // Add properties if necessary + ActionPool = RandomizedActionPool }; }