Refactor and update settings window

This commit is contained in:
Asriel Camora
2023-07-15 22:46:57 +04:00
parent eae91d6d02
commit 5cd9f10917
3 changed files with 212 additions and 72 deletions
+27
View File
@@ -2,6 +2,7 @@ using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics; using System.Numerics;
namespace Craftimizer.Plugin; namespace Craftimizer.Plugin;
@@ -131,4 +132,30 @@ internal static class ImGuiUtils
ImGui.PopFont(); ImGui.PopFont();
return ret; return ret;
} }
// https://gist.github.com/dougbinks/ef0962ef6ebe2cadae76c4e9f0586c69#file-imguiutils-h-L219
private static void UnderlineLastItem(Vector4 color)
{
var min = ImGui.GetItemRectMin();
var max = ImGui.GetItemRectMax();
min.Y = max.Y;
ImGui.GetWindowDrawList().AddLine(min, max, ImGui.ColorConvertFloat4ToU32(color), 1);
}
// https://gist.github.com/dougbinks/ef0962ef6ebe2cadae76c4e9f0586c69#file-imguiutils-h-L228
public static unsafe void Hyperlink(string text, string url)
{
ImGui.PushStyleColor(ImGuiCol.Text, *ImGui.GetStyleColorVec4(ImGuiCol.ButtonHovered));
ImGui.TextUnformatted(text);
ImGui.PopStyleColor();
if (ImGui.IsItemHovered())
{
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true });
UnderlineLastItem(*ImGui.GetStyleColorVec4(ImGuiCol.ButtonHovered));
ImGui.SetTooltip("Open in browser");
}
else
UnderlineLastItem(*ImGui.GetStyleColorVec4(ImGuiCol.Button));
}
} }
-4
View File
@@ -551,9 +551,7 @@ public unsafe class CraftingLog : Window
private CannotCraftReason CanCraftRecipe(Gearsets.GearsetItem[] items, CharacterStats stats) private CannotCraftReason CanCraftRecipe(Gearsets.GearsetItem[] items, CharacterStats stats)
{ {
if (!ClassJobUtils.IsClassJob((byte)Service.ClientState.LocalPlayer!.ClassJob.Id, RecipeClassJob)) if (!ClassJobUtils.IsClassJob((byte)Service.ClientState.LocalPlayer!.ClassJob.Id, RecipeClassJob))
{
return CannotCraftReason.WrongClassJob; return CannotCraftReason.WrongClassJob;
}
if (Recipe.IsSpecializationRequired && !stats.IsSpecialist) if (Recipe.IsSpecializationRequired && !stats.IsSpecialist)
return CannotCraftReason.SpecialistRequired; return CannotCraftReason.SpecialistRequired;
@@ -574,11 +572,9 @@ public unsafe class CraftingLog : Window
if (Recipe.StatusRequired.Value != null) if (Recipe.StatusRequired.Value != null)
{ {
if (!Service.ClientState.LocalPlayer.StatusList.Any(s => s.StatusId == Recipe.StatusRequired.Row)) if (!Service.ClientState.LocalPlayer.StatusList.Any(s => s.StatusId == Recipe.StatusRequired.Row))
{
return CannotCraftReason.RequiredStatus; return CannotCraftReason.RequiredStatus;
} }
} }
}
if (Recipe.RequiredCraftsmanship > stats.Craftsmanship) if (Recipe.RequiredCraftsmanship > stats.Craftsmanship)
return CannotCraftReason.CraftsmanshipTooLow; return CannotCraftReason.CraftsmanshipTooLow;
+185 -68
View File
@@ -1,15 +1,9 @@
using Craftimizer.Simulator;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Numerics; using System.Numerics;
using System.Diagnostics; using System.Diagnostics;
using System;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
@@ -29,89 +23,212 @@ public class SettingsWindow : Window
Size = SizeConstraints.Value.MinimumSize; Size = SizeConstraints.Value.MinimumSize;
} }
private static void DrawOption(string label, string tooltip, bool val, Action<bool> setter, ref bool isDirty)
{
if (ImGui.Checkbox(label, ref val))
{
setter(val);
isDirty = true;
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip(tooltip);
}
private static void DrawOption(string label, string tooltip, int val, Action<int> setter, ref bool isDirty)
{
ImGui.SetNextItemWidth(200);
if (ImGui.InputInt(label, ref val))
{
setter(val);
isDirty = true;
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip(tooltip);
}
private static void DrawOption(string label, string tooltip, float val, Action<float> setter, ref bool isDirty)
{
ImGui.SetNextItemWidth(200);
if (ImGui.InputFloat(label, ref val))
{
setter(val);
isDirty = true;
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip(tooltip);
}
public override void Draw() public override void Draw()
{ {
bool val;
float valF;
int valI;
ImGuiUtils.BeginGroupPanel("General"); ImGuiUtils.BeginGroupPanel("General");
var isDirty = false; var isDirty = false;
val = Config.OverrideUncraftability; DrawOption(
if (ImGui.Checkbox("Override uncraftability warning", ref val)) "Override uncraftability warning",
{ "Allow simulation for crafts that otherwise wouldn't be able to be crafted with your current gear",
Config.OverrideUncraftability = val; Config.OverrideUncraftability,
isDirty = true; v => Config.OverrideUncraftability = v,
} ref isDirty
);
val = Config.HideUnlearnedActions; DrawOption(
if (ImGui.Checkbox("Show only learned actions", ref val)) "Show only learned actions",
{ "Don't show crafting actions that haven't been learned yet with your current job on the simulator sidebar",
Config.HideUnlearnedActions = val; Config.HideUnlearnedActions,
isDirty = true; v => Config.HideUnlearnedActions = v,
} ref isDirty
);
val = Config.ConditionRandomness; DrawOption(
if (ImGui.Checkbox("Condition randomness", ref val)) "Hide combo actions",
{ "Don't show combo actions on the simulator sidebar",
Config.ConditionRandomness = val; Config.HideCombos,
isDirty = true; v => Config.HideCombos = v,
} ref isDirty
);
DrawOption(
"Condition randomness",
"Allows the simulator condition to fluctuate randomly like a real craft.\nTurns off when generating a macro.",
Config.ConditionRandomness,
v => Config.ConditionRandomness = v,
ref isDirty
);
ImGuiUtils.EndGroupPanel(); ImGuiUtils.EndGroupPanel();
ImGuiUtils.BeginGroupPanel("Solver"); ImGuiUtils.BeginGroupPanel("Solver");
ImGui.TextWrapped("Credit to altosock's Craftingway for the original algorithm"); ImGui.Text("Credit to altosock's ");
if (ImGui.Button("Open Craftingway")) ImGui.SameLine(0, 0);
Process.Start(new ProcessStartInfo { FileName = "https://craftingway.app", UseShellExecute = true }); ImGuiUtils.Hyperlink("Craftingway", "https://craftingway.app");
ImGui.SameLine(0, 0);
ImGui.Text(" for the original algorithm");
ImGuiHelpers.ScaledDummy(10); ImGuiHelpers.ScaledDummy(5);
var config = Config.SolverConfig; var config = Config.SolverConfig;
var isSolverDirty = false; var isSolverDirty = false;
valI = config.Iterations; DrawOption(
ImGui.SetNextItemWidth(200); "Iterations",
if (ImGui.InputInt("Iterations", ref valI)) "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,
config = config with { Iterations = valI }; v => config = config with { Iterations = v },
isSolverDirty = true; ref isSolverDirty
} );
valF = config.ScoreStorageThreshold; DrawOption(
ImGui.SetNextItemWidth(200); "Score Storage Threshold",
if (ImGui.InputFloat("Score Storage Threshold", ref valF)) "If a craft achieves this certain arbitrary score, the solver will throw away all other possible combinations in favor of that one. Only change this value if you absolutely know what you're doing.",
{ config.ScoreStorageThreshold,
config = config with { ScoreStorageThreshold = valF }; v => config = config with { ScoreStorageThreshold = v },
isSolverDirty = true; ref isSolverDirty
} );
valF = config.MaxScoreWeightingConstant; DrawOption(
ImGui.SetNextItemWidth(200); "Score Weighting Constant",
if (ImGui.InputFloat("Score Weighting Constant", ref valF)) "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,
config = config with { MaxScoreWeightingConstant = valF }; v => config = config with { MaxScoreWeightingConstant = v },
isSolverDirty = true; ref isSolverDirty
} );
valF = config.ExplorationConstant; DrawOption(
ImGui.SetNextItemWidth(200); "Exploration Constant",
if (ImGui.InputFloat("Exploration Constant", ref valF)) "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,
config = config with { ExplorationConstant = valF }; v => config = config with { ExplorationConstant = v },
isSolverDirty = true; ref isSolverDirty
} );
valI = config.MaxStepCount; DrawOption(
ImGui.SetNextItemWidth(200); "Max Step Count",
if (ImGui.InputInt("Max Step Count", ref valI)) "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,
config = config with { MaxStepCount = valI }; v => config = config with { MaxStepCount = v },
isSolverDirty = true; ref isSolverDirty
} );
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.",
config.MaxRolloutStepCount,
v => config = config with { MaxRolloutStepCount = v },
ref isSolverDirty
);
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.",
config.ForkCount,
v => config = config with { ForkCount = v },
ref isSolverDirty
);
DrawOption(
"Furcated 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.",
config.FurcatedActionCount,
v => config = config with { FurcatedActionCount = v },
ref isSolverDirty
);
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.",
config.StrictActions,
v => config = config with { StrictActions = v },
ref isSolverDirty
);
ImGuiHelpers.ScaledDummy(15);
ImGui.TextUnformatted("Score Weights");
ImGuiHelpers.ScaledDummy(5);
ImGui.TextUnformatted("All values must add up to 1. Otherwise, the Score Storage Threshold must be changed.");
ImGuiHelpers.ScaledDummy(10);
DrawOption(
"Progress",
"Amount of weight to give to the craft's progress.",
config.ScoreProgressBonus,
v => config = config with { ScoreProgressBonus = v },
ref isSolverDirty
);
DrawOption(
"Quality",
"Amount of weight to give to the craft's quality.",
config.ScoreQualityBonus,
v => config = config with { ScoreQualityBonus = v },
ref isSolverDirty
);
DrawOption(
"Durability",
"Amount of weight to give to the craft's remaining durability.",
config.ScoreDurabilityBonus,
v => config = config with { ScoreDurabilityBonus = v },
ref isSolverDirty
);
DrawOption(
"CP",
"Amount of weight to give to the craft's remaining CP.",
config.ScoreCPBonus,
v => config = config with { ScoreCPBonus = v },
ref isSolverDirty
);
DrawOption(
"Steps",
"Amount of weight to give to the craft's number of steps. The lower the step count, the higher the score.",
config.ScoreFewerStepsBonus,
v => config = config with { ScoreFewerStepsBonus = v },
ref isSolverDirty
);
if (ImGui.Button("Reset to defaults")) if (ImGui.Button("Reset to defaults"))
{ {