Move simulation and macro state to separate class
This commit is contained in:
@@ -0,0 +1,234 @@
|
|||||||
|
using Craftimizer.Plugin;
|
||||||
|
using Craftimizer.Simulator;
|
||||||
|
using Craftimizer.Simulator.Actions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Sim = Craftimizer.Simulator.Simulator;
|
||||||
|
using SimNoRandom = Craftimizer.Simulator.SimulatorNoRandom;
|
||||||
|
|
||||||
|
namespace Craftimizer.Utils;
|
||||||
|
|
||||||
|
internal sealed class SimulatedMacro
|
||||||
|
{
|
||||||
|
public readonly record struct Reliablity
|
||||||
|
{
|
||||||
|
public sealed class Param
|
||||||
|
{
|
||||||
|
private List<int> DataList { get; }
|
||||||
|
private ImGuiUtils.ViolinData? ViolinData { get; set; }
|
||||||
|
|
||||||
|
public int Max { get; private set; }
|
||||||
|
public int Min { get; private set; }
|
||||||
|
public float Median { get; private set; }
|
||||||
|
public float Average { get; private set; }
|
||||||
|
|
||||||
|
public Param()
|
||||||
|
{
|
||||||
|
DataList = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int value)
|
||||||
|
{
|
||||||
|
DataList.Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinalizeData()
|
||||||
|
{
|
||||||
|
if (DataList.Count == 0)
|
||||||
|
{
|
||||||
|
Average = Median = Max = Min = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Max = DataList.Max();
|
||||||
|
Min = DataList.Min();
|
||||||
|
if (DataList.Count % 2 == 0)
|
||||||
|
Median = (float)DataList.Order().Skip(DataList.Count / 2 - 1).Take(2).Average();
|
||||||
|
else
|
||||||
|
Median = DataList.Order().ElementAt(DataList.Count / 2);
|
||||||
|
Average = (float)DataList.Average();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImGuiUtils.ViolinData? GetViolinData(float barMax, int resolution, double bandwidth) =>
|
||||||
|
ViolinData ??=
|
||||||
|
Min != Max ?
|
||||||
|
new(DataList, 0, barMax, resolution, bandwidth) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly Param Progress = new();
|
||||||
|
public readonly Param Quality = new();
|
||||||
|
|
||||||
|
// Param is either collectability, quality, or hq%, depending on the recipe
|
||||||
|
public readonly Param ParamScore = new();
|
||||||
|
|
||||||
|
public Reliablity(in SimulationState startState, IEnumerable<ActionType> actions, int iterCount, RecipeData recipeData)
|
||||||
|
{
|
||||||
|
Func<SimulationState, int> getParam;
|
||||||
|
if (recipeData.Recipe.ItemResult.Value!.IsCollectable)
|
||||||
|
getParam = s => s.Collectability;
|
||||||
|
else if (recipeData.Recipe.RequiredQuality > 0)
|
||||||
|
{
|
||||||
|
var reqQual = recipeData.Recipe.RequiredQuality;
|
||||||
|
getParam = s => (int)((float)s.Quality / reqQual * 100);
|
||||||
|
}
|
||||||
|
else if (recipeData.RecipeInfo.MaxQuality > 0)
|
||||||
|
getParam = s => s.HQPercent;
|
||||||
|
else
|
||||||
|
getParam = s => 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < iterCount; ++i)
|
||||||
|
{
|
||||||
|
var sim = new Sim();
|
||||||
|
var (_, state, _) = sim.ExecuteMultiple(startState, actions);
|
||||||
|
Progress.Add(state.Progress);
|
||||||
|
Quality.Add(state.Quality);
|
||||||
|
ParamScore.Add(getParam(state));
|
||||||
|
}
|
||||||
|
Progress.FinalizeData();
|
||||||
|
Quality.FinalizeData();
|
||||||
|
ParamScore.FinalizeData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record Step
|
||||||
|
{
|
||||||
|
public ActionType Action { get; }
|
||||||
|
// State *after* executing the action
|
||||||
|
public ActionResponse Response { get; private set; }
|
||||||
|
public SimulationState State { get; private set; }
|
||||||
|
private Reliablity? Reliability { get; set; }
|
||||||
|
|
||||||
|
public Step(ActionType action, Sim sim, in SimulationState lastState, out SimulationState newState)
|
||||||
|
{
|
||||||
|
Action = action;
|
||||||
|
newState = Recalculate(sim, lastState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimulationState Recalculate(Sim sim, in SimulationState lastState)
|
||||||
|
{
|
||||||
|
(Response, State) = sim.Execute(lastState, Action);
|
||||||
|
Reliability = null;
|
||||||
|
return State;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reliablity GetReliability(in SimulationState initialState, IEnumerable<ActionType> actionSet, RecipeData recipeData) =>
|
||||||
|
Reliability ??=
|
||||||
|
new(initialState, actionSet, Service.Configuration.ReliabilitySimulationCount, recipeData);
|
||||||
|
};
|
||||||
|
|
||||||
|
private List<Step> Macro { get; set; } = new();
|
||||||
|
private SimulationState initialState;
|
||||||
|
public SimulationState InitialState
|
||||||
|
{
|
||||||
|
get => initialState;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (initialState != value)
|
||||||
|
{
|
||||||
|
initialState = value;
|
||||||
|
RecalculateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private object QueueLock { get; } = new();
|
||||||
|
private List<Step> QueuedSteps { get; set; } = new();
|
||||||
|
|
||||||
|
public SimulationState State => Macro.Count > 0 ? Macro[^1].State : InitialState;
|
||||||
|
|
||||||
|
public IEnumerable<ActionType> Actions => Macro.Select(m => m.Action);
|
||||||
|
public int Count => Macro.Count;
|
||||||
|
|
||||||
|
public (ActionType Action, ActionResponse Response, SimulationState State) this[int i]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var step = Macro[i];
|
||||||
|
return (step.Action, step.Response, step.State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reliablity GetReliability(RecipeData recipeData) =>
|
||||||
|
Macro.Count > 0 ?
|
||||||
|
Macro[^1].GetReliability(InitialState, Macro.Select(m => m.Action), recipeData) :
|
||||||
|
new(InitialState, Array.Empty<ActionType>(), 0, recipeData);
|
||||||
|
|
||||||
|
public void RemoveRange(int index, int count) =>
|
||||||
|
Macro.RemoveRange(index, count);
|
||||||
|
|
||||||
|
public void Clear() =>
|
||||||
|
Macro.Clear();
|
||||||
|
|
||||||
|
public void Add(ActionType action)
|
||||||
|
{
|
||||||
|
var sim = CreateSim();
|
||||||
|
Macro.Add(new(action, sim, State, out _));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(int index, ActionType action)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= Macro.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
var state = index == 0 ? InitialState : Macro[index - 1].State;
|
||||||
|
var sim = CreateSim();
|
||||||
|
Macro.Insert(index, new(action, sim, state, out state));
|
||||||
|
|
||||||
|
for (var i = index + 1; i < Macro.Count; i++)
|
||||||
|
state = Macro[i].Recalculate(sim, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= Macro.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
Macro.RemoveAt(index);
|
||||||
|
|
||||||
|
var state = index == 0 ? InitialState : Macro[index - 1].State;
|
||||||
|
var sim = CreateSim();
|
||||||
|
for (var i = index; i < Macro.Count; i++)
|
||||||
|
state = Macro[i].Recalculate(sim, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enqueue(ActionType action)
|
||||||
|
{
|
||||||
|
lock (QueueLock)
|
||||||
|
{
|
||||||
|
var lastState = QueuedSteps.Count > 0 ? QueuedSteps[^1].State : State;
|
||||||
|
QueuedSteps.Add(new(action, CreateSim(), lastState, out _));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearQueue()
|
||||||
|
{
|
||||||
|
lock (QueueLock)
|
||||||
|
{
|
||||||
|
QueuedSteps.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FlushQueue()
|
||||||
|
{
|
||||||
|
lock (QueueLock)
|
||||||
|
{
|
||||||
|
if (QueuedSteps.Count > 0)
|
||||||
|
{
|
||||||
|
Macro.AddRange(QueuedSteps);
|
||||||
|
QueuedSteps.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecalculateState()
|
||||||
|
{
|
||||||
|
var sim = CreateSim();
|
||||||
|
var lastState = InitialState;
|
||||||
|
for (var i = 0; i < Macro.Count; i++)
|
||||||
|
lastState = Macro[i].Recalculate(sim, lastState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Sim CreateSim() =>
|
||||||
|
Service.Configuration.ConditionRandomness ? new Sim() : new SimNoRandom();
|
||||||
|
}
|
||||||
@@ -77,125 +77,16 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
private List<int> HQIngredientCounts { get; set; }
|
private List<int> HQIngredientCounts { get; set; }
|
||||||
private int StartingQuality => RecipeData.CalculateStartingQuality(HQIngredientCounts);
|
private int StartingQuality => RecipeData.CalculateStartingQuality(HQIngredientCounts);
|
||||||
|
|
||||||
private readonly record struct SimulationReliablity
|
private SimulatedMacro Macro { get; set; } = new();
|
||||||
{
|
private SimulationState State => Macro.State;
|
||||||
public sealed class ParamReliability
|
private SimulatedMacro.Reliablity Reliability => Macro.GetReliability(RecipeData);
|
||||||
{
|
|
||||||
private List<int> DataList { get; }
|
|
||||||
private ImGuiUtils.ViolinData? ViolinData { get; set; }
|
|
||||||
|
|
||||||
public int Max { get; private set; }
|
|
||||||
public int Min { get; private set; }
|
|
||||||
public float Median { get; private set; }
|
|
||||||
public float Average { get; private set; }
|
|
||||||
|
|
||||||
public ParamReliability()
|
|
||||||
{
|
|
||||||
DataList = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(int value)
|
|
||||||
{
|
|
||||||
DataList.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FinalizeData()
|
|
||||||
{
|
|
||||||
if (DataList.Count == 0)
|
|
||||||
{
|
|
||||||
Average = Median = Max = Min = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Max = DataList.Max();
|
|
||||||
Min = DataList.Min();
|
|
||||||
if (DataList.Count % 2 == 0)
|
|
||||||
Median = (float)DataList.Order().Skip(DataList.Count / 2 - 1).Take(2).Average();
|
|
||||||
else
|
|
||||||
Median = DataList.Order().ElementAt(DataList.Count / 2);
|
|
||||||
Average = (float)DataList.Average();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImGuiUtils.ViolinData? GetViolinData(float barMax, int resolution, double bandwidth) =>
|
|
||||||
ViolinData ??=
|
|
||||||
Min != Max ?
|
|
||||||
new(DataList, 0, barMax, resolution, bandwidth) :
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly ParamReliability Progress = new();
|
|
||||||
public readonly ParamReliability Quality = new();
|
|
||||||
|
|
||||||
// Param is either collectability, quality, or hq%, depending on the recipe
|
|
||||||
public readonly ParamReliability Param = new();
|
|
||||||
|
|
||||||
public SimulationReliablity(in SimulationState startState, IEnumerable<ActionType> actions, int iterCount, RecipeData recipeData)
|
|
||||||
{
|
|
||||||
Func<SimulationState, int> getParam;
|
|
||||||
if (recipeData.Recipe.ItemResult.Value!.IsCollectable)
|
|
||||||
getParam = s => s.Collectability;
|
|
||||||
else if (recipeData.Recipe.RequiredQuality > 0)
|
|
||||||
{
|
|
||||||
var reqQual = recipeData.Recipe.RequiredQuality;
|
|
||||||
getParam = s => (int)((float)s.Quality / reqQual * 100);
|
|
||||||
}
|
|
||||||
else if (recipeData.RecipeInfo.MaxQuality > 0)
|
|
||||||
getParam = s => s.HQPercent;
|
|
||||||
else
|
|
||||||
getParam = s => 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < iterCount; ++i)
|
|
||||||
{
|
|
||||||
var sim = new Sim();
|
|
||||||
var (_, state, _) = sim.ExecuteMultiple(startState, actions);
|
|
||||||
Progress.Add(state.Progress);
|
|
||||||
Quality.Add(state.Quality);
|
|
||||||
Param.Add(getParam(state));
|
|
||||||
}
|
|
||||||
Progress.FinalizeData();
|
|
||||||
Quality.FinalizeData();
|
|
||||||
Param.FinalizeData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed record SimulatedActionStep
|
|
||||||
{
|
|
||||||
public ActionType Action { get; }
|
|
||||||
// State *after* executing the action
|
|
||||||
public ActionResponse Response { get; private set; }
|
|
||||||
public SimulationState State { get; private set; }
|
|
||||||
private SimulationReliablity? Reliability { get; set; }
|
|
||||||
|
|
||||||
public SimulatedActionStep(ActionType action, Sim sim, in SimulationState lastState, out SimulationState newState)
|
|
||||||
{
|
|
||||||
Action = action;
|
|
||||||
newState = Recalculate(sim, lastState);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimulationState Recalculate(Sim sim, in SimulationState lastState)
|
|
||||||
{
|
|
||||||
(Response, State) = sim.Execute(lastState, Action);
|
|
||||||
Reliability = null;
|
|
||||||
return State;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimulationReliablity GetReliability(in SimulationState initialState, IEnumerable<ActionType> actionSet, RecipeData recipeData) =>
|
|
||||||
Reliability ??=
|
|
||||||
new(initialState, actionSet, Service.Configuration.ReliabilitySimulationCount, recipeData);
|
|
||||||
};
|
|
||||||
|
|
||||||
private List<SimulatedActionStep> Macro { get; set; } = new();
|
|
||||||
private SimulationState InitialState { get; set; }
|
|
||||||
private SimulationState State => Macro.Count > 0 ? Macro[^1].State : InitialState;
|
|
||||||
private SimulationReliablity Reliability => Macro.Count > 0 ? Macro[^1].GetReliability(InitialState, Macro.Select(m => m.Action), RecipeData) : new(InitialState, Array.Empty<ActionType>(), 0, RecipeData);
|
|
||||||
private ActionType[] DefaultActions { get; }
|
private ActionType[] DefaultActions { get; }
|
||||||
private Action<IEnumerable<ActionType>>? MacroSetter { get; set; }
|
private Action<IEnumerable<ActionType>>? MacroSetter { get; set; }
|
||||||
|
|
||||||
private CancellationTokenSource? SolverTokenSource { get; set; }
|
private CancellationTokenSource? SolverTokenSource { get; set; }
|
||||||
private Exception? SolverException { get; set; }
|
private Exception? SolverException { get; set; }
|
||||||
private int? SolverStartStepCount { get; set; }
|
private int? SolverStartStepCount { get; set; }
|
||||||
private object? SolverQueueLock { get; set; }
|
|
||||||
private List<SimulatedActionStep>? SolverQueuedSteps { get; set; }
|
|
||||||
private Solver.Solver? SolverObject { get; set; }
|
private Solver.Solver? SolverObject { get; set; }
|
||||||
private bool SolverRunning => SolverTokenSource != null;
|
private bool SolverRunning => SolverTokenSource != null;
|
||||||
|
|
||||||
@@ -263,7 +154,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
TryFlushSolvedSteps();
|
Macro.FlushQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
@@ -1100,14 +991,14 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
new("Condition", default, null, 0, 0, null, State.Condition)
|
new("Condition", default, null, 0, 0, null, State.Condition)
|
||||||
};
|
};
|
||||||
if (RecipeData.Recipe.ItemResult.Value!.IsCollectable)
|
if (RecipeData.Recipe.ItemResult.Value!.IsCollectable)
|
||||||
datas.Add(new("Collectability", Colors.HQ, Reliability.Param, State.Collectability, State.MaxCollectability, $"{State.Collectability}", null));
|
datas.Add(new("Collectability", Colors.HQ, Reliability.ParamScore, State.Collectability, State.MaxCollectability, $"{State.Collectability}", null));
|
||||||
else if (RecipeData.Recipe.RequiredQuality > 0)
|
else if (RecipeData.Recipe.RequiredQuality > 0)
|
||||||
{
|
{
|
||||||
var qualityPercent = (float)State.Quality / RecipeData.Recipe.RequiredQuality * 100;
|
var qualityPercent = (float)State.Quality / RecipeData.Recipe.RequiredQuality * 100;
|
||||||
datas.Add(new("Quality %%", Colors.HQ, Reliability.Param, qualityPercent, 100, $"{qualityPercent:0}%", null));
|
datas.Add(new("Quality %%", Colors.HQ, Reliability.ParamScore, qualityPercent, 100, $"{qualityPercent:0}%", null));
|
||||||
}
|
}
|
||||||
else if (RecipeData.RecipeInfo.MaxQuality > 0)
|
else if (RecipeData.RecipeInfo.MaxQuality > 0)
|
||||||
datas.Add(new("HQ %%", Colors.HQ, Reliability.Param, State.HQPercent, 100, $"{State.HQPercent}%", null));
|
datas.Add(new("HQ %%", Colors.HQ, Reliability.ParamScore, State.HQPercent, 100, $"{State.HQPercent}%", null));
|
||||||
DrawBars(datas);
|
DrawBars(datas);
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
@@ -1162,7 +1053,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly record struct BarData(string Name, Vector4 Color, SimulationReliablity.ParamReliability? Reliability, float Value, float Max, string? Caption, Condition? Condition);
|
private readonly record struct BarData(string Name, Vector4 Color, SimulatedMacro.Reliablity.Param? Reliability, float Value, float Max, string? Caption, Condition? Condition);
|
||||||
private void DrawBars(IEnumerable<BarData> bars)
|
private void DrawBars(IEnumerable<BarData> bars)
|
||||||
{
|
{
|
||||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||||
@@ -1264,7 +1155,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
{
|
{
|
||||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var imageSize = ImGui.GetFrameHeight() * 2;
|
var imageSize = ImGui.GetFrameHeight() * 2;
|
||||||
var lastState = InitialState;
|
var lastState = Macro.InitialState;
|
||||||
|
|
||||||
using var panel = ImRaii2.GroupPanel("Macro", -1, out var availSpace);
|
using var panel = ImRaii2.GroupPanel("Macro", -1, out var availSpace);
|
||||||
ImGui.Dummy(new(0, imageSize));
|
ImGui.Dummy(new(0, imageSize));
|
||||||
@@ -1378,7 +1269,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
}
|
}
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste))
|
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste))
|
||||||
Service.Plugin.CopyMacro(Macro.Select(s => s.Action).ToArray());
|
Service.Plugin.CopyMacro(Macro.Actions.ToArray());
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
ImGui.SetTooltip("Copy to Clipboard");
|
ImGui.SetTooltip("Copy to Clipboard");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
@@ -1438,7 +1329,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(popupSaveAsMacroName))
|
if (!string.IsNullOrWhiteSpace(popupSaveAsMacroName))
|
||||||
{
|
{
|
||||||
var newMacro = new Macro() { Name = popupSaveAsMacroName, Actions = Macro.Select(s => s.Action).ToArray() };
|
var newMacro = new Macro() { Name = popupSaveAsMacroName, Actions = Macro.Actions.ToArray() };
|
||||||
Service.Configuration.AddMacro(newMacro);
|
Service.Configuration.AddMacro(newMacro);
|
||||||
MacroSetter = actions =>
|
MacroSetter = actions =>
|
||||||
{
|
{
|
||||||
@@ -1606,16 +1497,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
SolverTokenSource?.Cancel();
|
SolverTokenSource?.Cancel();
|
||||||
SolverTokenSource = new();
|
SolverTokenSource = new();
|
||||||
SolverException = null;
|
SolverException = null;
|
||||||
if (SolverQueueLock is { })
|
Macro.ClearQueue();
|
||||||
{
|
|
||||||
lock (SolverQueueLock)
|
|
||||||
{
|
|
||||||
SolverQueuedSteps!.Clear();
|
|
||||||
SolverQueueLock = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SolverQueueLock = new();
|
|
||||||
SolverQueuedSteps ??= new();
|
|
||||||
|
|
||||||
RevertPreviousMacro();
|
RevertPreviousMacro();
|
||||||
|
|
||||||
@@ -1665,7 +1547,7 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
using (SolverObject = new Solver.Solver(config, state) { Token = token })
|
using (SolverObject = new Solver.Solver(config, state) { Token = token })
|
||||||
{
|
{
|
||||||
SolverObject.OnLog += Log.Debug;
|
SolverObject.OnLog += Log.Debug;
|
||||||
SolverObject.OnNewAction += QueueSolverStep;
|
SolverObject.OnNewAction += Macro.Enqueue;
|
||||||
SolverObject.Start();
|
SolverObject.Start();
|
||||||
_ = SolverObject.GetTask().GetAwaiter().GetResult();
|
_ = SolverObject.GetTask().GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
@@ -1681,95 +1563,34 @@ public sealed class MacroEditor : Window, IDisposable
|
|||||||
|
|
||||||
private void SaveMacro()
|
private void SaveMacro()
|
||||||
{
|
{
|
||||||
MacroSetter?.Invoke(Macro.Select(s => s.Action));
|
MacroSetter?.Invoke(Macro.Actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RecalculateState()
|
private void RecalculateState()
|
||||||
{
|
{
|
||||||
InitialState = new SimulationState(new(CharacterStats, RecipeData.RecipeInfo, StartingQuality));
|
Macro.InitialState = new SimulationState(new(CharacterStats, RecipeData.RecipeInfo, StartingQuality));
|
||||||
var sim = CreateSim();
|
|
||||||
var lastState = InitialState;
|
|
||||||
for (var i = 0; i < Macro.Count; i++)
|
|
||||||
lastState = Macro[i].Recalculate(sim, lastState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Sim CreateSim() =>
|
|
||||||
Service.Configuration.ConditionRandomness ? new Sim() : new SimNoRandom();
|
|
||||||
|
|
||||||
private static Sim CreateSim(in SimulationState state) =>
|
private static Sim CreateSim(in SimulationState state) =>
|
||||||
Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state };
|
Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state };
|
||||||
|
|
||||||
private void AddStep(ActionType action, int index = -1)
|
private void AddStep(ActionType action)
|
||||||
{
|
{
|
||||||
if (index < -1 || index >= Macro.Count)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
|
||||||
if (SolverRunning)
|
if (SolverRunning)
|
||||||
throw new InvalidOperationException("Cannot add steps while solver is running");
|
throw new InvalidOperationException("Cannot add steps while solver is running");
|
||||||
if (!SolverRunning)
|
if (!SolverRunning)
|
||||||
SolverStartStepCount = null;
|
SolverStartStepCount = null;
|
||||||
|
|
||||||
if (index == -1)
|
Macro.Add(action);
|
||||||
{
|
|
||||||
var sim = CreateSim();
|
|
||||||
Macro.Add(new(action, sim, State, out _));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var state = index == 0 ? InitialState : Macro[index - 1].State;
|
|
||||||
var sim = CreateSim();
|
|
||||||
Macro.Insert(index, new(action, sim, state, out state));
|
|
||||||
|
|
||||||
for (var i = index + 1; i < Macro.Count; i++)
|
|
||||||
state = Macro[i].Recalculate(sim, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QueueSolverStep(ActionType action)
|
|
||||||
{
|
|
||||||
if (!SolverRunning)
|
|
||||||
throw new InvalidOperationException("Cannot queue steps while solver isn't running");
|
|
||||||
lock (SolverQueueLock!)
|
|
||||||
{
|
|
||||||
var lastState = SolverQueuedSteps!.Count > 0 ? SolverQueuedSteps[^1].State : State;
|
|
||||||
SolverQueuedSteps.Add(new(action, CreateSim(), lastState, out _));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TryFlushSolvedSteps()
|
|
||||||
{
|
|
||||||
if (SolverQueueLock == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (SolverQueueLock!)
|
|
||||||
{
|
|
||||||
if (SolverQueuedSteps!.Count > 0)
|
|
||||||
{
|
|
||||||
Macro.AddRange(SolverQueuedSteps);
|
|
||||||
SolverQueuedSteps.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SolverRunning)
|
|
||||||
{
|
|
||||||
SolverQueuedSteps.Clear();
|
|
||||||
SolverQueueLock = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveStep(int index)
|
private void RemoveStep(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= Macro.Count)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
|
||||||
if (SolverRunning)
|
if (SolverRunning)
|
||||||
throw new InvalidOperationException("Cannot remove steps while solver is running");
|
throw new InvalidOperationException("Cannot remove steps while solver is running");
|
||||||
SolverStartStepCount = null;
|
SolverStartStepCount = null;
|
||||||
|
|
||||||
Macro.RemoveAt(index);
|
Macro.RemoveAt(index);
|
||||||
|
|
||||||
var state = index == 0 ? InitialState : Macro[index - 1].State;
|
|
||||||
var sim = CreateSim();
|
|
||||||
for (var i = index; i < Macro.Count; i++)
|
|
||||||
state = Macro[i].Recalculate(sim, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
Reference in New Issue
Block a user