Plugin: Add Raphael

This commit is contained in:
Asriel Camora
2024-11-28 02:38:01 -08:00
parent 9a39ef936e
commit 150c2c9716
10 changed files with 265 additions and 135 deletions
+2
View File
@@ -13,7 +13,9 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly> <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup> </PropertyGroup>
+19 -1
View File
@@ -226,7 +226,25 @@ internal static class ImGuiUtils
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)
{ {
Arc(MathF.PI / 2, MathF.PI / 2 - MathF.Tau * Math.Clamp(value, 0, 1), radius, ratio, backgroundColor, filledColor); float startAngle, endAngle;
// https://github.com/ocornut/imgui/commit/c895e987adf746a997b655c64a6a8916c549ff6f#diff-d750e175eb584ba76bc560b8e54cf113ccbb31dd33f75078c1588925e197a3afR1304-R1310
if (value < 0)
{
const float ArcSize = 0.15f;
startAngle = -value % 1;
endAngle = startAngle + ArcSize;
startAngle = float.Lerp(MathF.PI / 2, -3 * MathF.PI / 2, startAngle);
endAngle = float.Lerp(MathF.PI / 2, -3 * MathF.PI / 2, endAngle);
}
else
{
startAngle = MathF.PI / 2;
endAngle = MathF.PI / 2 - MathF.Tau * Math.Clamp(value, 0, 1);
}
Arc(startAngle, endAngle, radius, ratio, backgroundColor, filledColor);
} }
public sealed class ViolinData public sealed class ViolinData
+8
View File
@@ -151,6 +151,14 @@ public sealed class Plugin : IDalamudPlugin
ClipboardWindow = new(macros); ClipboardWindow = new(macros);
} }
public IActiveNotification DisplaySolverWarning(string text) =>
DisplayNotification(new()
{
Content = text,
Title = "Solver Warning",
Type = NotificationType.Warning
});
public IActiveNotification DisplayNotification(Notification notification) public IActiveNotification DisplayNotification(Notification notification)
{ {
var ret = Service.NotificationManager.AddNotification(notification); var ret = Service.NotificationManager.AddNotification(notification);
+10 -2
View File
@@ -191,9 +191,11 @@ internal static class DynamicBars
var progressWidth = availSpace.Value - percentWidth - spacing; var progressWidth = availSpace.Value - percentWidth - spacing;
var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage); var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage);
fraction = Math.Clamp(fraction, 0, 1);
using (ImRaii.PushColor(ImGuiCol.FrameBg, progressColors.Background)) using (ImRaii.PushColor(ImGuiCol.FrameBg, progressColors.Background))
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, progressColors.Foreground)) using (ImRaii.PushColor(ImGuiCol.PlotHistogram, progressColors.Foreground))
ImGui.ProgressBar(Math.Clamp(fraction, 0, 1), new(progressWidth, ImGui.GetFrameHeight()), string.Empty); ImGui.ProgressBar(solver.IsIndeterminate ? (float)-ImGui.GetTime() : fraction, new(progressWidth, ImGui.GetFrameHeight()), string.Empty);
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
DrawProgressBarTooltip(solver); DrawProgressBarTooltip(solver);
ImGui.SameLine(0, spacing); ImGui.SameLine(0, spacing);
@@ -203,9 +205,15 @@ internal static class DynamicBars
public static void DrawProgressBarTooltip(Solver.Solver solver) public static void DrawProgressBarTooltip(Solver.Solver solver)
{ {
var tooltip = $"Solver Progress: {solver.ProgressValue:N0} / {solver.ProgressMax:N0}"; string tooltip;
if (solver.IsIndeterminate)
tooltip = "Initializing Solver";
else
{
tooltip = $"Solver Progress: {solver.ProgressValue:N0} / {solver.ProgressMax:N0}";
if (solver.ProgressValue > solver.ProgressMax) 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); ImGuiUtils.TooltipWrapped(tooltip);
} }
} }
+40 -4
View File
@@ -1,6 +1,7 @@
using Craftimizer.Plugin; using Craftimizer.Plugin;
using Craftimizer.Simulator; using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions; using Craftimizer.Simulator.Actions;
using DotNext.Collections.Generic;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -95,6 +96,7 @@ internal sealed class SimulatedMacro
private sealed record Step private sealed record Step
{ {
public ActionType Action { get; } public ActionType Action { get; }
public bool IsEphemeral { get; }
// State *after* executing the action // State *after* executing the action
public ActionResponse Response { get; private set; } public ActionResponse Response { get; private set; }
public SimulationState State { get; private set; } public SimulationState State { get; private set; }
@@ -107,9 +109,10 @@ internal sealed class SimulatedMacro
} }
// Call recalculate after this please! // Call recalculate after this please!
public Step(ActionType action) public Step(ActionType action, bool isEphemeral = false)
{ {
Action = action; Action = action;
IsEphemeral = isEphemeral;
} }
public SimulationState Recalculate(Sim sim, in SimulationState lastState) public SimulationState Recalculate(Sim sim, in SimulationState lastState)
@@ -125,6 +128,7 @@ internal sealed class SimulatedMacro
}; };
private List<Step> Macro { get; set; } = []; private List<Step> Macro { get; set; } = [];
private SimulationState initialState; private SimulationState initialState;
public SimulationState InitialState public SimulationState InitialState
{ {
@@ -140,6 +144,7 @@ internal sealed class SimulatedMacro
} }
private object QueueLock { get; } = new(); private object QueueLock { get; } = new();
private List<Step> QueuedSteps { get; set; } = []; private List<Step> QueuedSteps { get; set; } = [];
private List<Step> QueuedEphemeralSteps { get; set; } = [];
public SimulationState FirstState => Macro.Count > 0 ? Macro[0].State : InitialState; public SimulationState FirstState => Macro.Count > 0 ? Macro[0].State : InitialState;
public SimulationState State => Macro.Count > 0 ? Macro[^1].State : InitialState; public SimulationState State => Macro.Count > 0 ? Macro[^1].State : InitialState;
@@ -158,7 +163,7 @@ internal sealed class SimulatedMacro
public Reliablity GetReliability(RecipeData recipeData, Index? idx = null) => public Reliablity GetReliability(RecipeData recipeData, Index? idx = null) =>
Macro.Count > 0 ? Macro.Count > 0 ?
Macro[idx ?? ^1].GetReliability(InitialState, Macro.Select(m => m.Action), recipeData) : Macro[idx ?? ^1].GetReliability(InitialState, Actions.ToArray(), recipeData) :
new(InitialState, Array.Empty<ActionType>(), 0, recipeData); new(InitialState, Array.Empty<ActionType>(), 0, recipeData);
private void TryRecalculateFrom(int index) private void TryRecalculateFrom(int index)
@@ -213,6 +218,15 @@ internal sealed class SimulatedMacro
TryRecalculateFrom(Math.Min(fromIdx, toIdx)); TryRecalculateFrom(Math.Min(fromIdx, toIdx));
} }
public void RemoveEphemeral()
{
for (var i = Macro.Count - 1; i >= 0; --i)
{
if (Macro[i].IsEphemeral)
Macro.RemoveAt(i);
}
}
public int Enqueue(ActionType action, int? maxSize = null) public int Enqueue(ActionType action, int? maxSize = null)
{ {
lock (QueueLock) lock (QueueLock)
@@ -220,8 +234,25 @@ internal sealed class SimulatedMacro
if (maxSize is { } size && QueuedSteps.Count + Macro.Count >= size) if (maxSize is { } size && QueuedSteps.Count + Macro.Count >= size)
return size; return size;
QueuedEphemeralSteps.Clear();
QueuedSteps.Add(new(action)); QueuedSteps.Add(new(action));
return QueuedSteps.Count + Macro.Count; return Macro.Count + QueuedSteps.Count;
}
}
public int EnqueueEphemeral(IEnumerable<ActionType> actions, int? maxSize = null)
{
lock (QueueLock)
{
QueuedEphemeralSteps.Clear();
foreach (var action in actions)
{
if (maxSize is { } size && QueuedSteps.Count + QueuedEphemeralSteps.Count + Macro.Count >= size)
return size;
QueuedEphemeralSteps.Add(new(action, true));
}
return Macro.Count + QueuedSteps.Count + QueuedEphemeralSteps.Count;
} }
} }
@@ -230,6 +261,7 @@ internal sealed class SimulatedMacro
lock (QueueLock) lock (QueueLock)
{ {
QueuedSteps.Clear(); QueuedSteps.Clear();
QueuedEphemeralSteps.Clear();
} }
} }
@@ -237,11 +269,15 @@ internal sealed class SimulatedMacro
{ {
lock (QueueLock) lock (QueueLock)
{ {
if (QueuedSteps.Count > 0) if (QueuedSteps.Count > 0 || QueuedEphemeralSteps.Count > 0)
{ {
RemoveEphemeral();
var startIdx = Macro.Count; var startIdx = Macro.Count;
Macro.AddRange(QueuedSteps); Macro.AddRange(QueuedSteps);
Macro.AddRange(QueuedEphemeralSteps);
QueuedSteps.Clear(); QueuedSteps.Clear();
QueuedEphemeralSteps.Clear();
TryRecalculateFrom(startIdx); TryRecalculateFrom(startIdx);
} }
} }
+6 -2
View File
@@ -1182,7 +1182,7 @@ public sealed class MacroEditor : Window, IDisposable
var actionBase = action.Base(); var actionBase = action.Base();
var failedAction = response != ActionResponse.UsedAction; var failedAction = response != ActionResponse.UsedAction;
using var id = ImRaii.PushId(i); using var id = ImRaii.PushId(i);
if (ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One)) if (ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One) && !SolverRunning)
RemoveStep(i); RemoveStep(i);
if (response is ActionResponse.ActionNotUnlocked || if (response is ActionResponse.ActionNotUnlocked ||
( (
@@ -1550,10 +1550,14 @@ public sealed class MacroEditor : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += a => Macro.Enqueue(a); solver.OnNewAction += a => Macro.Enqueue(a);
solver.OnSuggestSolution += a => Macro.EnqueueEphemeral(a.Actions);
SolverObject = solver; SolverObject = solver;
solver.Start(); solver.Start();
_ = solver.GetTask().GetAwaiter().GetResult(); var t = solver.GetTask();
_ = t.ContinueWith(_ => Macro.RemoveEphemeral());
_ = t.GetAwaiter().GetResult();
token.ThrowIfCancellationRequested(); token.ThrowIfCancellationRequested();
+2 -1
View File
@@ -844,7 +844,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
{ {
var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage); var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage);
ImGuiUtils.ArcProgress( ImGuiUtils.ArcProgress(
fraction, solver.IsIndeterminate ? (float)-ImGui.GetTime() : fraction,
windowHeight / 2f + 2, windowHeight / 2f + 2,
.5f, .5f,
ImGui.ColorConvertFloat4ToU32(progressColors.Background), ImGui.ColorConvertFloat4ToU32(progressColors.Background),
@@ -1187,6 +1187,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
BestMacroSolver = solver; BestMacroSolver = solver;
solver.Start(); solver.Start();
var solution = solver.GetTask().GetAwaiter().GetResult(); var solution = solver.GetTask().GetAwaiter().GetResult();
+42 -3
View File
@@ -149,6 +149,7 @@ public sealed class Settings : Window, IDisposable
SolverAlgorithm.Stepwise => "Stepwise", SolverAlgorithm.Stepwise => "Stepwise",
SolverAlgorithm.StepwiseForked => "Stepwise Forked", SolverAlgorithm.StepwiseForked => "Stepwise Forked",
SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic", SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic",
SolverAlgorithm.Raphael => "Optimal (Slow)",
_ => "Unknown", _ => "Unknown",
}; };
@@ -163,6 +164,9 @@ public sealed class Settings : Window, IDisposable
SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " + SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " +
"selected from the solvers, and each one is equally " + "selected from the solvers, and each one is equally " +
"used as a starting point", "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" _ => "Unknown"
}; };
@@ -527,6 +531,8 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
if (config.Algorithm != SolverAlgorithm.Raphael)
{
DrawOption( DrawOption(
"Target Iterations", "Target Iterations",
"The total number of iterations to run per crafting step. " + "The total number of iterations to run per crafting step. " +
@@ -593,7 +599,7 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
using (var d = 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( DrawOption(
"Max Core Count", "Max Core Count",
"The number of cores to use when solving. You should use as many " + "The number of cores to use when solving. You should use as many " +
@@ -609,7 +615,7 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
using (var d = 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( DrawOption(
"Fork Count", "Fork Count",
"Split the number of iterations across different solvers. In general, " + "Split the number of iterations across different solvers. In general, " +
@@ -626,7 +632,7 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
using (var d = ImRaii.Disabled(config.Algorithm is not SolverAlgorithm.StepwiseGenetic)) using (ImRaii.Disabled(config.Algorithm is not SolverAlgorithm.StepwiseGenetic))
DrawOption( DrawOption(
"Elitist Action Count", "Elitist Action Count",
"On every craft step, pick this many top solutions and use them as " + "On every craft step, pick this many top solutions and use them as " +
@@ -640,6 +646,26 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
} }
else
{
DrawOption(
"Ensure 100% Reliability",
"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
);
DrawOption(
"Backload Progress",
"Find a rotation that only uses Progress-increasing actions " +
"at the end of the rotation. May speed up solve times.",
config.BackloadProgress,
v => config = config with { BackloadProgress = v },
ref isDirty
);
}
}
using (var panel = ImRaii2.GroupPanel("Action Pool", -1, out var poolWidth)) using (var panel = ImRaii2.GroupPanel("Action Pool", -1, out var poolWidth))
{ {
@@ -657,6 +683,8 @@ public sealed class Settings : Window, IDisposable
} }
using (var panel = ImRaii2.GroupPanel("Advanced", -1, out _)) using (var panel = ImRaii2.GroupPanel("Advanced", -1, out _))
{
if (config.Algorithm != SolverAlgorithm.Raphael)
{ {
DrawOption( DrawOption(
"Max Rollout Step Count", "Max Rollout Step Count",
@@ -680,6 +708,17 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
} }
else
{
DrawOption(
"Unsound Branch Pruning",
"TBD",
config.UnsoundBranchPruning,
v => config = config with { UnsoundBranchPruning = v },
ref isDirty
);
}
}
using (var panel = ImRaii2.GroupPanel("Score Weights (Advanced)", -1, out _)) using (var panel = ImRaii2.GroupPanel("Score Weights (Advanced)", -1, out _))
{ {
+1
View File
@@ -611,6 +611,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += EnqueueAction; solver.OnNewAction += EnqueueAction;
SolverObject = solver; SolverObject = solver;
solver.Start(); solver.Start();
+14 -1
View File
@@ -28,6 +28,11 @@
"System.IO.Hashing": "8.0.0" "System.IO.Hashing": "8.0.0"
} }
}, },
"Raphael.Net": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "J/D1pw2MT52hENysYs7SA++PBT4sHwUcPnTzjb9/lLigNJazob4v7WbBe2enKpfDAI6hO8al7p2Qlt2258fk8g=="
},
"System.IO.Hashing": { "System.IO.Hashing": {
"type": "Transitive", "type": "Transitive",
"resolved": "8.0.0", "resolved": "8.0.0",
@@ -40,9 +45,17 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Craftimizer.Simulator": "[1.0.0, )", "Craftimizer.Simulator": "[1.0.0, )",
"DotNext": "[5.14.0, )" "DotNext": "[5.14.0, )",
"Raphael.Net": "[1.0.0, )"
} }
} }
},
"net8.0-windows7.0/win-x64": {
"Raphael.Net": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "J/D1pw2MT52hENysYs7SA++PBT4sHwUcPnTzjb9/lLigNJazob4v7WbBe2enKpfDAI6hO8al7p2Qlt2258fk8g=="
}
} }
} }
} }