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>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</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)
{
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
+8
View File
@@ -151,6 +151,14 @@ public sealed class Plugin : IDalamudPlugin
ClipboardWindow = new(macros);
}
public IActiveNotification DisplaySolverWarning(string text) =>
DisplayNotification(new()
{
Content = text,
Title = "Solver Warning",
Type = NotificationType.Warning
});
public IActiveNotification DisplayNotification(Notification 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 progressColors = Colors.GetSolverProgressColors(solver.ProgressStage);
fraction = Math.Clamp(fraction, 0, 1);
using (ImRaii.PushColor(ImGuiCol.FrameBg, progressColors.Background))
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())
DrawProgressBarTooltip(solver);
ImGui.SameLine(0, spacing);
@@ -203,9 +205,15 @@ internal static class DynamicBars
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)
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);
}
}
+40 -4
View File
@@ -1,6 +1,7 @@
using Craftimizer.Plugin;
using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using DotNext.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -95,6 +96,7 @@ internal sealed class SimulatedMacro
private sealed record Step
{
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; }
@@ -107,9 +109,10 @@ internal sealed class SimulatedMacro
}
// Call recalculate after this please!
public Step(ActionType action)
public Step(ActionType action, bool isEphemeral = false)
{
Action = action;
IsEphemeral = isEphemeral;
}
public SimulationState Recalculate(Sim sim, in SimulationState lastState)
@@ -125,6 +128,7 @@ internal sealed class SimulatedMacro
};
private List<Step> Macro { get; set; } = [];
private SimulationState initialState;
public SimulationState InitialState
{
@@ -140,6 +144,7 @@ internal sealed class SimulatedMacro
}
private object QueueLock { get; } = new();
private List<Step> QueuedSteps { get; set; } = [];
private List<Step> QueuedEphemeralSteps { get; set; } = [];
public SimulationState FirstState => Macro.Count > 0 ? Macro[0].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) =>
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);
private void TryRecalculateFrom(int index)
@@ -213,6 +218,15 @@ internal sealed class SimulatedMacro
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)
{
lock (QueueLock)
@@ -220,8 +234,25 @@ internal sealed class SimulatedMacro
if (maxSize is { } size && QueuedSteps.Count + Macro.Count >= size)
return size;
QueuedEphemeralSteps.Clear();
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)
{
QueuedSteps.Clear();
QueuedEphemeralSteps.Clear();
}
}
@@ -237,11 +269,15 @@ internal sealed class SimulatedMacro
{
lock (QueueLock)
{
if (QueuedSteps.Count > 0)
if (QueuedSteps.Count > 0 || QueuedEphemeralSteps.Count > 0)
{
RemoveEphemeral();
var startIdx = Macro.Count;
Macro.AddRange(QueuedSteps);
Macro.AddRange(QueuedEphemeralSteps);
QueuedSteps.Clear();
QueuedEphemeralSteps.Clear();
TryRecalculateFrom(startIdx);
}
}
+6 -2
View File
@@ -1182,7 +1182,7 @@ public sealed class MacroEditor : Window, IDisposable
var actionBase = action.Base();
var failedAction = response != ActionResponse.UsedAction;
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);
if (response is ActionResponse.ActionNotUnlocked ||
(
@@ -1550,10 +1550,14 @@ public sealed class MacroEditor : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += a => Macro.Enqueue(a);
solver.OnSuggestSolution += a => Macro.EnqueueEphemeral(a.Actions);
SolverObject = solver;
solver.Start();
_ = solver.GetTask().GetAwaiter().GetResult();
var t = solver.GetTask();
_ = t.ContinueWith(_ => Macro.RemoveEphemeral());
_ = t.GetAwaiter().GetResult();
token.ThrowIfCancellationRequested();
+2 -1
View File
@@ -844,7 +844,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
{
var progressColors = Colors.GetSolverProgressColors(solver.ProgressStage);
ImGuiUtils.ArcProgress(
fraction,
solver.IsIndeterminate ? (float)-ImGui.GetTime() : fraction,
windowHeight / 2f + 2,
.5f,
ImGui.ColorConvertFloat4ToU32(progressColors.Background),
@@ -1187,6 +1187,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
BestMacroSolver = solver;
solver.Start();
var solution = solver.GetTask().GetAwaiter().GetResult();
+42 -3
View File
@@ -149,6 +149,7 @@ public sealed class Settings : Window, IDisposable
SolverAlgorithm.Stepwise => "Stepwise",
SolverAlgorithm.StepwiseForked => "Stepwise Forked",
SolverAlgorithm.StepwiseGenetic => "Stepwise Genetic",
SolverAlgorithm.Raphael => "Optimal (Slow)",
_ => "Unknown",
};
@@ -163,6 +164,9 @@ public sealed class Settings : Window, IDisposable
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"
};
@@ -527,6 +531,8 @@ public sealed class Settings : Window, IDisposable
ref isDirty
);
if (config.Algorithm != SolverAlgorithm.Raphael)
{
DrawOption(
"Target Iterations",
"The total number of iterations to run per crafting step. " +
@@ -593,7 +599,7 @@ public sealed class Settings : Window, IDisposable
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(
"Max Core Count",
"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
);
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(
"Fork Count",
"Split the number of iterations across different solvers. In general, " +
@@ -626,7 +632,7 @@ public sealed class Settings : Window, IDisposable
ref isDirty
);
using (var d = ImRaii.Disabled(config.Algorithm is not SolverAlgorithm.StepwiseGenetic))
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 " +
@@ -640,6 +646,26 @@ public sealed class Settings : Window, IDisposable
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))
{
@@ -657,6 +683,8 @@ public sealed class Settings : Window, IDisposable
}
using (var panel = ImRaii2.GroupPanel("Advanced", -1, out _))
{
if (config.Algorithm != SolverAlgorithm.Raphael)
{
DrawOption(
"Max Rollout Step Count",
@@ -680,6 +708,17 @@ public sealed class Settings : Window, IDisposable
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 _))
{
+1
View File
@@ -611,6 +611,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += EnqueueAction;
SolverObject = solver;
solver.Start();
+14 -1
View File
@@ -28,6 +28,11 @@
"System.IO.Hashing": "8.0.0"
}
},
"Raphael.Net": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "J/D1pw2MT52hENysYs7SA++PBT4sHwUcPnTzjb9/lLigNJazob4v7WbBe2enKpfDAI6hO8al7p2Qlt2258fk8g=="
},
"System.IO.Hashing": {
"type": "Transitive",
"resolved": "8.0.0",
@@ -40,9 +45,17 @@
"type": "Project",
"dependencies": {
"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=="
}
}
}
}