Refactor and move around config/settings window

This commit is contained in:
Asriel Camora
2024-03-22 23:59:00 -07:00
parent 28c271c714
commit 895e2a4460
7 changed files with 189 additions and 97 deletions
+6 -1
View File
@@ -85,10 +85,15 @@ public class Configuration : IPluginConfiguration
public IReadOnlyList<Macro> Macros => macros; public IReadOnlyList<Macro> Macros => macros;
public int ReliabilitySimulationCount { get; set; } = 500; public int ReliabilitySimulationCount { get; set; } = 500;
public bool ConditionRandomness { get; set; } = true; public bool ConditionRandomness { get; set; } = true;
[JsonConverter(typeof(PopulateConverter))] [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))] [JsonConverter(typeof(PopulateConverter))]
public SolverConfig SynthHelperSolverConfig { get; set; } = SolverConfig.SynthHelperDefault; public SolverConfig SynthHelperSolverConfig { get; set; } = SolverConfig.SynthHelperDefault;
public bool EnableSynthHelper { get; set; } = true; public bool EnableSynthHelper { get; set; } = true;
public bool DisableSynthHelperOnMacro { get; set; } = true; public bool DisableSynthHelperOnMacro { get; set; } = true;
public bool ShowOptimalMacroStat { get; set; } = true; public bool ShowOptimalMacroStat { get; set; } = true;
+1 -1
View File
@@ -1603,7 +1603,7 @@ public sealed class MacroEditor : Window, IDisposable
private void CalculateBestMacroTask(SimulationState state, CancellationToken token) private void CalculateBestMacroTask(SimulationState state, CancellationToken token)
{ {
var config = Service.Configuration.SimulatorSolverConfig; var config = Service.Configuration.EditorSolverConfig;
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
+1 -1
View File
@@ -239,7 +239,7 @@ public sealed class MacroList : Window, IDisposable
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight))
OpenEditor(macro); OpenEditor(macro);
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
ImGuiUtils.Tooltip("Open in Simulator"); ImGuiUtils.Tooltip("Open in Macro Editor");
ImGui.SameLine(0, spacing); ImGui.SameLine(0, spacing);
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.PencilAlt, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.PencilAlt, miniRowHeight))
ShowRenamePopup(macro); ShowRenamePopup(macro);
+5 -5
View File
@@ -400,7 +400,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
if (ImGui.Button("View Saved Macros", new(availWidth, 0))) if (ImGui.Button("View Saved Macros", new(availWidth, 0)))
Service.Plugin.OpenMacroListWindow(); 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<ActionType>(), null); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), Enumerable.Empty<ActionType>(), null);
} }
@@ -932,7 +932,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight))
Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), actions, state.MacroEditorSetter); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), actions, state.MacroEditorSetter);
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
ImGuiUtils.Tooltip("Open in Simulator"); ImGuiUtils.Tooltip("Open in Macro Editor");
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight))
Service.Plugin.CopyMacro(actions); Service.Plugin.CopyMacro(actions);
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
@@ -1085,7 +1085,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
{ {
var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo);
var state = new SimulationState(input); var state = new SimulationState(input);
var config = Service.Configuration.SimulatorSolverConfig; var config = Service.Configuration.RecipeNoteSolverConfig;
var mctsConfig = new MCTSConfig(config); var mctsConfig = new MCTSConfig(config);
var simulator = new SimulatorNoRandom(); var simulator = new SimulatorNoRandom();
List<Macro> macros = new(Service.Configuration.Macros); List<Macro> macros = new(Service.Configuration.Macros);
@@ -1116,7 +1116,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
{ {
var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo);
var state = new SimulationState(input); var state = new SimulationState(input);
var config = Service.Configuration.SimulatorSolverConfig; var config = Service.Configuration.RecipeNoteSolverConfig;
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
@@ -1140,7 +1140,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
{ {
var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo); var input = new SimulationInput(CharacterStats!, RecipeData!.RecipeInfo);
var state = new SimulationState(input); var state = new SimulationState(input);
var config = Service.Configuration.SimulatorSolverConfig; var config = Service.Configuration.RecipeNoteSolverConfig;
var mctsConfig = new MCTSConfig(config); var mctsConfig = new MCTSConfig(config);
var simulator = new SimulatorNoRandom(); var simulator = new SimulatorNoRandom();
var macros = Service.CommunityMacros.RetrieveRotations(input.Recipe.RLvl, token).GetAwaiter().GetResult(); var macros = Service.CommunityMacros.RetrieveRotations(input.Recipe.RLvl, token).GetAwaiter().GetResult();
+80 -53
View File
@@ -165,7 +165,8 @@ public sealed class Settings : Window, IDisposable
if (ImGui.BeginTabBar("settingsTabBar")) if (ImGui.BeginTabBar("settingsTabBar"))
{ {
DrawTabGeneral(); DrawTabGeneral();
DrawTabSimulator(); DrawTabRecipeNote();
DrawTabMacroEditor();
if (Config.EnableSynthHelper) if (Config.EnableSynthHelper)
DrawTabSynthHelper(); DrawTabSynthHelper();
DrawTabAbout(); DrawTabAbout();
@@ -194,51 +195,6 @@ public sealed class Settings : Window, IDisposable
ref isDirty 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( DrawOption(
"Show Only One Macro Stat in Crafting Log", "Show Only One Macro Stat in Crafting Log",
"Only one stat will be shown for a macro. If a craft will be finished, quality " + "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.", "as necessary to get a more favorable outcome.",
config.Iterations, config.Iterations,
1000, 1000,
500000, 1000000,
v => config = config with { Iterations = v }, v => config = config with { Iterations = v },
ref isDirty 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) if (!tab)
return; return;
@@ -819,11 +775,82 @@ public sealed class Settings : Window, IDisposable
var isDirty = false; var isDirty = false;
var solverConfig = Config.SimulatorSolverConfig; DrawOption(
DrawSolverConfig(ref solverConfig, SolverConfig.SimulatorDefault, out var isSolverDirty); "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) 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; isDirty = true;
} }
@@ -842,7 +869,7 @@ public sealed class Settings : Window, IDisposable
var isDirty = false; var isDirty = false;
DrawOption( DrawOption(
"Pin Window", "Pin Helper Window",
"Pins the synthesis helper to the right of your synthesis window. Disabling this will " + "Pins the synthesis helper to the right of your synthesis window. Disabling this will " +
"allow you to move it around.", "allow you to move it around.",
Config.PinSynthHelperToWindow, Config.PinSynthHelperToWindow,
+1 -1
View File
@@ -426,7 +426,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
"can vary wildly depending on the solver's settings."); "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<ActionType>(), null); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), Enumerable.Empty<ActionType>(), null);
} }
+95 -35
View File
@@ -1,4 +1,5 @@
using Craftimizer.Simulator.Actions; using Craftimizer.Simulator.Actions;
using System.Collections.Frozen;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Craftimizer.Solver; namespace Craftimizer.Solver;
@@ -37,7 +38,7 @@ public readonly record struct SolverConfig
public SolverConfig() public SolverConfig()
{ {
Iterations = 100000; Iterations = 100_000;
ScoreStorageThreshold = 1f; ScoreStorageThreshold = 1f;
MaxScoreWeightingConstant = 0.1f; MaxScoreWeightingConstant = 0.1f;
ExplorationConstant = 4; ExplorationConstant = 4;
@@ -56,63 +57,122 @@ public readonly record struct SolverConfig
ScoreCP = .05f; ScoreCP = .05f;
ScoreSteps = .05f; ScoreSteps = .05f;
ActionPool = DefaultActionPool; ActionPool = DeterministicActionPool;
Algorithm = SolverAlgorithm.StepwiseFurcated; Algorithm = SolverAlgorithm.StepwiseFurcated;
} }
public static ActionType[] OptimizeActionPool(IEnumerable<ActionType> actions) => public static ActionType[] OptimizeActionPool(IEnumerable<ActionType> actions) =>
actions.Order().ToArray(); 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.StandardTouchCombo,
ActionType.AdvancedTouchCombo, ActionType.AdvancedTouchCombo,
ActionType.FocusedTouchCombo, ActionType.FocusedTouchCombo,
ActionType.FocusedSynthesisCombo, ActionType.FocusedSynthesisCombo,
ActionType.TrainedFinesse, });
ActionType.PrudentSynthesis,
ActionType.Groundwork, // Same as deterministic, but with condition-specific actions added
ActionType.AdvancedTouch, public static readonly ActionType[] RandomizedActionPool = OptimizeActionPool(new[]
ActionType.CarefulSynthesis, {
ActionType.TrainedEye,
ActionType.DelicateSynthesis,
ActionType.PreparatoryTouch,
ActionType.Reflect,
ActionType.PrudentTouch,
ActionType.Manipulation,
ActionType.MuscleMemory, ActionType.MuscleMemory,
ActionType.ByregotsBlessing, ActionType.Reflect,
ActionType.WasteNot2, ActionType.TrainedEye,
ActionType.BasicSynthesis, ActionType.BasicSynthesis,
ActionType.Innovation, ActionType.CarefulSynthesis,
ActionType.GreatStrides, ActionType.FocusedSynthesis,
ActionType.StandardTouch, ActionType.Groundwork,
ActionType.Veneration, ActionType.DelicateSynthesis,
ActionType.WasteNot, ActionType.IntensiveSynthesis,
ActionType.MastersMend, ActionType.PrudentSynthesis,
ActionType.BasicTouch, 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<ActionType> InefficientActions = new HashSet<ActionType>(new[] public static readonly FrozenSet<ActionType> InefficientActions =
{ new[]
ActionType.CarefulObservation, {
ActionType.HeartAndSoul, ActionType.CarefulObservation,
ActionType.FinalAppraisal ActionType.HeartAndSoul,
}); ActionType.FinalAppraisal
}.ToFrozenSet();
public static readonly IReadOnlySet<ActionType> RiskyActions = new HashSet<ActionType>(new[] public static readonly FrozenSet<ActionType> RiskyActions =
{ new[]
ActionType.RapidSynthesis, {
ActionType.HastyTouch, 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 public static readonly SolverConfig SynthHelperDefault = new SolverConfig() with
{ {
// Add properties if necessary ActionPool = RandomizedActionPool
}; };
} }