Remove ref passing, but keep devirtualizations

This commit is contained in:
Asriel Camora
2024-03-16 13:24:26 -07:00
parent 3223bdcbfb
commit ec77f1d021
48 changed files with 411 additions and 787 deletions
+21 -5
View File
@@ -1,4 +1,5 @@
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Diagnostics.dotTrace; using BenchmarkDotNet.Diagnostics.dotTrace;
using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Jobs;
using Craftimizer.Simulator; using Craftimizer.Simulator;
@@ -6,10 +7,12 @@ using Craftimizer.Solver;
namespace Craftimizer.Benchmark; namespace Craftimizer.Benchmark;
[SimpleJob(RuntimeMoniker.Net70, baseline: true)] [SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.Net80)] [SimpleJob(RuntimeMoniker.Net80, baseline: true)]
[MinColumn, Q1Column, Q3Column, MaxColumn] [MinColumn, Q1Column, Q3Column, MaxColumn]
[DotTraceDiagnoser] //[DotTraceDiagnoser]
[MemoryDiagnoser]
[DisassemblyDiagnoser(maxDepth: 500, exportGithubMarkdown: false, exportHtml: true)]
public class Bench public class Bench
{ {
public record struct HashWrapper<T>(T Data) where T : notnull public record struct HashWrapper<T>(T Data) where T : notnull
@@ -95,12 +98,25 @@ public class Bench
[ParamsSource(nameof(Configs))] [ParamsSource(nameof(Configs))]
public HashWrapper<SolverConfig> Config { get; set; } public HashWrapper<SolverConfig> Config { get; set; }
[Benchmark] // [Benchmark]
public async Task<float> Solve() public async Task<float> SolveAsync()
{ {
var solver = new Solver.Solver(Config, State); var solver = new Solver.Solver(Config, State);
solver.Start(); solver.Start();
var (_, s) = await solver.GetTask().ConfigureAwait(false); var (_, s) = await solver.GetTask().ConfigureAwait(false);
return (float)s.Quality / s.Input.Recipe.MaxQuality; return (float)s.Quality / s.Input.Recipe.MaxQuality;
} }
[Benchmark]
public (float MaxScore, SolverSolution Solution) Solve()
{
var config = new MCTSConfig(Config.Data);
var solver = new MCTS(config, State);
var progress = 0;
solver.Search(Config.Data.Iterations, ref progress, CancellationToken.None);
var solution = solver.Solution();
return (solver.MaxScore, solution);
}
} }
+1 -2
View File
@@ -935,7 +935,6 @@ public sealed class MacroEditor : Window, IDisposable
using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero); using var _color3 = ImRaii.PushColor(ImGuiCol.ButtonHovered, Vector4.Zero);
using var _color2 = ImRaii.PushColor(ImGuiCol.ButtonActive, Vector4.Zero); using var _color2 = ImRaii.PushColor(ImGuiCol.ButtonActive, Vector4.Zero);
using var _alpha = ImRaii.PushStyle(ImGuiStyleVar.DisabledAlpha, ImGui.GetStyle().DisabledAlpha * .5f); using var _alpha = ImRaii.PushStyle(ImGuiStyleVar.DisabledAlpha, ImGui.GetStyle().DisabledAlpha * .5f);
var cost = 0;
foreach (var category in Enum.GetValues<ActionCategory>()) foreach (var category in Enum.GetValues<ActionCategory>())
{ {
if (category == ActionCategory.Combo) if (category == ActionCategory.Combo)
@@ -953,7 +952,7 @@ public sealed class MacroEditor : Window, IDisposable
if (i < itemCount) if (i < itemCount)
{ {
var actionBase = actions[i].Base(); var actionBase = actions[i].Base();
var canUse = actionBase.CanUse(sim, ref cost); var canUse = actionBase.CanUse(sim);
if (ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, !canUse ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One)) if (ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, !canUse ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One))
AddStep(actions[i]); AddStep(actions[i]);
if (!canUse && if (!canUse &&
+6 -23
View File
@@ -1,27 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class AdvancedTouch : BaseAction internal sealed class AdvancedTouch() : BaseAction(
ActionCategory.Quality, level: 84, actionId: 100411,
increasesQuality: true,
defaultCPCost: 46, defaultEfficiency: 150)
{ {
public int CostDefault = 46; public override int CPCost(Simulator s) =>
public int CostOptimal = 18; s.ActionStates.TouchComboIdx == 2 ? 18 : 46;
public int EfficiencyDefault = 150;
public AdvancedTouch()
{
Category = ActionCategory.Quality;
Level = 84;
ActionId = 100411;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = s.ActionStates.TouchComboIdx == 2 ? CostOptimal : CostDefault;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = EfficiencyDefault;
}
} }
+4 -3
View File
@@ -1,7 +1,8 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class AdvancedTouchCombo : BaseComboAction<StandardTouchCombo, AdvancedTouch> internal sealed class AdvancedTouchCombo() : BaseComboAction<StandardTouchCombo, AdvancedTouch>(
ActionType.StandardTouchCombo, ActionType.AdvancedTouch, 18 * 3
)
{ {
public override ActionType ActionTypeA => ActionType.StandardTouchCombo;
public override ActionType ActionTypeB => ActionType.AdvancedTouch;
} }
+48 -46
View File
@@ -2,39 +2,46 @@ using System.Text;
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
public abstract class BaseAction public abstract class BaseAction(
ActionCategory category, int level, uint actionId,
int macroWaitTime = 3,
bool increasesProgress = false, bool increasesQuality = false,
int durabilityCost = 10, bool increasesStepCount = true,
int defaultCPCost = 0,
int defaultEfficiency = 0,
float defaultSuccessRate = 1)
{ {
// Non-instanced properties // Non-instanced properties
// Metadata // Metadata
public ActionCategory Category; public readonly ActionCategory Category = category;
public int Level; public readonly int Level = level;
// Doesn't matter from which class, we'll use the sheet to extrapolate the rest // Doesn't matter from which class, we'll use the sheet to extrapolate the rest
public uint ActionId; public readonly uint ActionId = actionId;
// Seconds // Seconds
public int MacroWaitTime = 3; public readonly int MacroWaitTime = macroWaitTime;
// Action properties // Action properties
public bool IncreasesProgress; public readonly bool IncreasesProgress = increasesProgress;
public bool IncreasesQuality; public readonly bool IncreasesQuality = increasesQuality;
public int DurabilityCost = 10; public readonly int DurabilityCost = durabilityCost;
public bool IncreasesStepCount = true; public readonly bool IncreasesStepCount = increasesStepCount;
public int EfficiencyFactor;
public float SuccessRateFactor = 1;
// Instanced properties // Instanced properties
public abstract void CPCost(Simulator s, ref int cost); public readonly int DefaultCPCost = defaultCPCost;
public readonly int DefaultEfficiency = defaultEfficiency;
public readonly float DefaultSuccessRate = defaultSuccessRate;
public virtual void Efficiency(Simulator s, ref int eff) // Instanced properties
{ public virtual int CPCost(Simulator s) =>
eff = EfficiencyFactor; DefaultCPCost;
}
public virtual void SuccessRate(Simulator s, ref float success) public virtual int Efficiency(Simulator s) =>
{ DefaultEfficiency;
success = SuccessRateFactor;
} public virtual float SuccessRate(Simulator s) =>
DefaultSuccessRate;
// Return true if it can be in the action pool now or in the future // Return true if it can be in the action pool now or in the future
// e.g. if Heart and Soul is already used, it is impossible to use it again // e.g. if Heart and Soul is already used, it is impossible to use it again
@@ -44,23 +51,18 @@ public abstract class BaseAction
// Return true if it can be used now // Return true if it can be used now
// This already assumes that IsPossible returns true *at some point before* // This already assumes that IsPossible returns true *at some point before*
public virtual bool CouldUse(Simulator s, ref int cost) public virtual bool CouldUse(Simulator s) =>
s.CP >= CPCost(s);
public bool CanUse(Simulator s) =>
IsPossible(s) && CouldUse(s);
public virtual void Use(Simulator s)
{ {
CPCost(s, ref cost); if (s.RollSuccess(SuccessRate(s)))
return s.CP >= cost; UseSuccess(s);
}
public bool CanUse(Simulator s, ref int cost) => s.ReduceCP(CPCost(s));
IsPossible(s) && CouldUse(s, ref cost);
public virtual void Use(Simulator s, ref int cost, ref float success, ref int eff)
{
SuccessRate(s, ref success);
if (s.RollSuccess(success))
UseSuccess(s, ref eff);
CPCost(s, ref cost);
s.ReduceCP(cost);
s.ReduceDurability(DurabilityCost); s.ReduceDurability(DurabilityCost);
if (s.Durability > 0) if (s.Durability > 0)
@@ -79,9 +81,9 @@ public abstract class BaseAction
s.ActiveEffects.DecrementDuration(); s.ActiveEffects.DecrementDuration();
} }
public virtual void UseSuccess(Simulator s, ref int eff) public virtual void UseSuccess(Simulator s)
{ {
Efficiency(s, ref eff); var eff = Efficiency(s);
if (eff != 0) if (eff != 0)
{ {
if (IncreasesProgress) if (IncreasesProgress)
@@ -93,28 +95,28 @@ public abstract class BaseAction
public virtual string GetTooltip(Simulator s, bool addUsability) public virtual string GetTooltip(Simulator s, bool addUsability)
{ {
var cost = CPCost(s);
var eff = Efficiency(s);
var success = SuccessRate(s);
var builder = new StringBuilder(); var builder = new StringBuilder();
int cost = 0; if (addUsability && !CanUse(s))
float success = 1f;
if (addUsability && !CanUse(s, ref cost))
builder.AppendLine($"Cannot Use"); builder.AppendLine($"Cannot Use");
builder.AppendLine($"Level {Level}"); builder.AppendLine($"Level {Level}");
if (cost != 0) if (cost != 0)
builder.AppendLine($"-{s.CalculateCPCost(cost)} CP"); builder.AppendLine($"-{s.CalculateCPCost(cost)} CP");
if (DurabilityCost != 0) if (DurabilityCost != 0)
builder.AppendLine($"-{s.CalculateDurabilityCost(DurabilityCost)} Durability"); builder.AppendLine($"-{s.CalculateDurabilityCost(DurabilityCost)} Durability");
Efficiency(s, ref cost); if (eff != 0)
if (cost != 0)
{ {
if (IncreasesProgress) if (IncreasesProgress)
builder.AppendLine($"+{s.CalculateProgressGain(cost)} Progress"); builder.AppendLine($"+{s.CalculateProgressGain(eff)} Progress");
if (IncreasesQuality) if (IncreasesQuality)
builder.AppendLine($"+{s.CalculateQualityGain(cost)} Quality"); builder.AppendLine($"+{s.CalculateQualityGain(eff)} Quality");
} }
if (!IncreasesStepCount) if (!IncreasesStepCount)
builder.AppendLine($"Does Not Increase Step Count"); builder.AppendLine($"Does Not Increase Step Count");
SuccessRate(s, ref success); if (success != 1)
if (Math.Abs(success - 1f) > float.Epsilon)
builder.AppendLine($"{s.CalculateSuccessRate(success) * 100:##}% Success Rate"); builder.AppendLine($"{s.CalculateSuccessRate(success) * 100:##}% Success Rate");
return builder.ToString(); return builder.ToString();
} }
+18 -10
View File
@@ -2,19 +2,27 @@ using System.Text;
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal abstract class BaseBuffAction : BaseAction internal abstract class BaseBuffAction(
ActionCategory category, int level, uint actionId,
EffectType effect, int duration,
int macroWaitTime = 2,
bool increasesProgress = false, bool increasesQuality = false,
int durabilityCost = 0, bool increasesStepCount = true,
int defaultCPCost = 0,
int defaultEfficiency = 0,
float defaultSuccessRate = 1) :
BaseAction(
category, level, actionId,
macroWaitTime,
increasesProgress, increasesQuality,
durabilityCost, increasesStepCount,
defaultCPCost, defaultEfficiency, defaultSuccessRate)
{ {
public BaseBuffAction()
{
MacroWaitTime = 2;
DurabilityCost = 0;
}
// Non-instanced properties // Non-instanced properties
public EffectType Effect; public readonly EffectType Effect = effect;
public int Duration = 1; public readonly int Duration = duration;
public override void UseSuccess(Simulator s, ref int eff) => public override void UseSuccess(Simulator s) =>
s.AddEffect(Effect, Duration); s.AddEffect(Effect, Duration);
public override string GetTooltip(Simulator s, bool addUsability) public override string GetTooltip(Simulator s, bool addUsability)
+13 -10
View File
@@ -1,17 +1,20 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
public abstract class BaseComboAction : BaseAction public abstract class BaseComboAction(
ActionType actionTypeA, ActionType actionTypeB,
BaseAction actionA, BaseAction actionB,
int? defaultCPCost = null) :
BaseAction(
ActionCategory.Combo, Math.Max(actionA.Level, actionA.Level), actionB.ActionId,
increasesProgress: actionA.IncreasesProgress || actionB.IncreasesProgress,
increasesQuality: actionA.IncreasesQuality || actionB.IncreasesQuality,
defaultCPCost: defaultCPCost ?? (actionA.DefaultCPCost + actionB.DefaultCPCost))
{ {
public abstract ActionType ActionTypeA { get; } public readonly ActionType ActionTypeA = actionTypeA;
public abstract ActionType ActionTypeB { get; } public readonly ActionType ActionTypeB = actionTypeB;
public BaseComboAction() protected bool BaseCouldUse(Simulator s) =>
{ base.CouldUse(s);
Category = ActionCategory.Combo;
}
protected bool BaseCouldUse(Simulator s, ref int cost) =>
base.CouldUse(s, ref cost);
private static bool VerifyDurability2(int durabilityA, int durability, in Effects effects) private static bool VerifyDurability2(int durabilityA, int durability, in Effects effects)
{ {
+13 -23
View File
@@ -1,36 +1,26 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal abstract class BaseComboAction<A, B> : BaseComboAction where A : BaseAction, new() where B : BaseAction, new() internal abstract class BaseComboAction<A, B>(
ActionType actionTypeA, ActionType actionTypeB,
int? baseCPCost = null) :
BaseComboAction(
actionTypeA, actionTypeB,
ActionA, ActionB,
baseCPCost
) where A : BaseAction, new() where B : BaseAction, new()
{ {
protected static readonly A ActionA = new(); protected static readonly A ActionA = new();
protected static readonly B ActionB = new(); protected static readonly B ActionB = new();
protected BaseComboAction()
{
Level = ActionB.Level;
ActionId = ActionB.ActionId;
IncreasesProgress = ActionA.IncreasesProgress || ActionB.IncreasesProgress;
IncreasesQuality = ActionA.IncreasesQuality || ActionB.IncreasesQuality;
}
public override void CPCost(Simulator s, ref int cost)
{
var costTmp = 0;
ActionA.CPCost(s, ref costTmp);
cost += costTmp;
ActionB.CPCost(s, ref costTmp);
cost += costTmp;
}
public override bool IsPossible(Simulator s) => ActionA.IsPossible(s) && ActionB.IsPossible(s); public override bool IsPossible(Simulator s) => ActionA.IsPossible(s) && ActionB.IsPossible(s);
public override bool CouldUse(Simulator s, ref int cost) => public override bool CouldUse(Simulator s) =>
BaseCouldUse(s, ref cost) && VerifyDurability2(s, ActionA.DurabilityCost); BaseCouldUse(s) && VerifyDurability2(s, ActionA.DurabilityCost);
public override void Use(Simulator s, ref int cost, ref float success, ref int eff) public override void Use(Simulator s)
{ {
ActionA.Use(s, ref cost, ref success, ref eff); ActionA.Use(s);
ActionB.Use(s, ref cost, ref success, ref eff); ActionB.Use(s);
} }
public override string GetTooltip(Simulator s, bool addUsability) => public override string GetTooltip(Simulator s, bool addUsability) =>
+8 -21
View File
@@ -1,26 +1,13 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class BasicSynthesis : BaseAction internal sealed class BasicSynthesis() : BaseAction(
ActionCategory.Synthesis, 1, 100001,
increasesProgress: true,
defaultCPCost: 0,
defaultEfficiency: 100
)
{ {
public int CP;
public int EfficiencyNormal = 100;
public int EfficiencyGood = 120;
public BasicSynthesis()
{
Category = ActionCategory.Synthesis;
IncreasesProgress = true;
ActionId = 100001;
Level = 1;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
// Basic Synthesis Mastery Trait // Basic Synthesis Mastery Trait
public override void Efficiency(Simulator s, ref int eff) public override int Efficiency(Simulator s) =>
{ s.Input.Stats.Level >= 31 ? 120 : 100;
eff = s.Input.Stats.Level >= 31 ? EfficiencyGood : EfficiencyNormal;
}
} }
+5 -20
View File
@@ -1,25 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class BasicTouch : BaseAction internal sealed class BasicTouch() : BaseAction(
ActionCategory.Quality, 5, 100002,
increasesQuality: true,
defaultCPCost: 18,
defaultEfficiency: 100)
{ {
public int CP = 18;
public int eff = 100;
public BasicTouch()
{
Category = ActionCategory.Quality;
Level = 5;
ActionId = 100002;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = this.eff;
}
} }
+12 -24
View File
@@ -1,32 +1,20 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class ByregotsBlessing : BaseAction internal sealed class ByregotsBlessing() : BaseAction(
ActionCategory.Quality, 50, 100339,
increasesQuality: true,
defaultCPCost: 24,
defaultEfficiency: 100)
{ {
public int CP = 24; public override int Efficiency(Simulator s) =>
100 + (20 * s.GetEffectStrength(EffectType.InnerQuiet));
public ByregotsBlessing() public override bool CouldUse(Simulator s) =>
s.HasEffect(EffectType.InnerQuiet) && base.CouldUse(s);
public override void UseSuccess(Simulator s)
{ {
Category = ActionCategory.Quality; base.UseSuccess(s);
Level = 50;
ActionId = 100339;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 100 + (20 * s.GetEffectStrength(EffectType.InnerQuiet));
}
public override bool CouldUse(Simulator s, ref int cost) => s.HasEffect(EffectType.InnerQuiet) && base.CouldUse(s, ref cost);
public override void UseSuccess(Simulator s, ref int eff)
{
base.UseSuccess(s, ref eff);
s.RemoveEffect(EffectType.InnerQuiet); s.RemoveEffect(EffectType.InnerQuiet);
} }
} }
+9 -20
View File
@@ -1,30 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class CarefulObservation : BaseAction internal sealed class CarefulObservation() : BaseAction(
ActionCategory.Other, 55, 100395,
durabilityCost: 0, increasesStepCount: false,
defaultCPCost: 0
)
{ {
public int CP = 0;
public CarefulObservation()
{
Category = ActionCategory.Other;
Level = 55;
ActionId = 100395;
MacroWaitTime = 3;
DurabilityCost = 0;
IncreasesStepCount = false;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override bool IsPossible(Simulator s) => public override bool IsPossible(Simulator s) =>
base.IsPossible(s) && s.Input.Stats.IsSpecialist && s.ActionStates.CarefulObservationCount < 3; base.IsPossible(s) && s.Input.Stats.IsSpecialist && s.ActionStates.CarefulObservationCount < 3;
public override bool CouldUse(Simulator s, ref int cost) => s.ActionStates.CarefulObservationCount < 3; public override bool CouldUse(Simulator s) =>
s.ActionStates.CarefulObservationCount < 3;
public override void UseSuccess(Simulator s, ref int eff) => s.StepCondition(); public override void UseSuccess(Simulator s) =>
s.StepCondition();
public override string GetTooltip(Simulator s, bool addUsability) => public override string GetTooltip(Simulator s, bool addUsability) =>
$"{base.GetTooltip(s, addUsability)}Specialist Only\n"; $"{base.GetTooltip(s, addUsability)}Specialist Only\n";
+8 -22
View File
@@ -1,27 +1,13 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class CarefulSynthesis : BaseAction internal sealed class CarefulSynthesis() : BaseAction(
ActionCategory.Synthesis, 62, 100203,
increasesProgress: true,
defaultCPCost: 7,
defaultEfficiency: 150
)
{ {
public int CP = 7;
public int EfficiencyNormal = 150;
public int EfficiencyMastery = 180;
public CarefulSynthesis()
{
Category = ActionCategory.Synthesis;
Level = 62;
ActionId = 100203;
IncreasesProgress = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
// Careful Synthesis Mastery Trait // Careful Synthesis Mastery Trait
public override void Efficiency(Simulator s, ref int eff) public override int Efficiency(Simulator s) =>
{ s.Input.Stats.Level >= 82 ? 180 : 150;
eff = s.Input.Stats.Level >= 82 ? EfficiencyMastery : EfficiencyNormal;
}
} }
+6 -21
View File
@@ -1,26 +1,11 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class DelicateSynthesis : BaseAction internal sealed class DelicateSynthesis() : BaseAction(
ActionCategory.Synthesis, 76, 100323,
increasesProgress: true, increasesQuality: true,
defaultCPCost: 32,
defaultEfficiency: 100
)
{ {
public int CP = 32;
public int Eff = 100;
public DelicateSynthesis()
{
Category = ActionCategory.Synthesis;
Level = 76;
ActionId = 100323;
IncreasesProgress = true;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = Eff;
}
} }
+5 -16
View File
@@ -1,21 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class FinalAppraisal : BaseBuffAction internal sealed class FinalAppraisal() : BaseBuffAction(
ActionCategory.Synthesis, 42, 19012,
EffectType.FinalAppraisal, duration: 4,
increasesStepCount: false,
defaultCPCost: 1)
{ {
public int CP = 1;
public FinalAppraisal()
{
Category = ActionCategory.Synthesis;
Level = 42;
ActionId = 19012;
Effect = EffectType.FinalAppraisal;
Duration = 4;
IncreasesStepCount = false;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
} }
+9 -28
View File
@@ -1,32 +1,13 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class FocusedSynthesis : BaseAction internal sealed class FocusedSynthesis() : BaseAction(
ActionCategory.Synthesis, 67, 100235,
increasesProgress: true,
defaultCPCost: 5,
defaultEfficiency: 200,
defaultSuccessRate: 0.50f
)
{ {
public int CP = 5; public override float SuccessRate(Simulator s) =>
public int Eff = 200; s.ActionStates.Observed ? 1.00f : 0.50f;
public float SuccessNormal = 0.50f;
public float SuccessObserved = 1.00f;
public FocusedSynthesis()
{
Category = ActionCategory.Synthesis;
Level = 67;
ActionId = 100235;
IncreasesProgress = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = Eff;
}
public override void SuccessRate(Simulator s, ref float success)
{
success = s.ActionStates.Observed ? SuccessObserved : SuccessNormal;
}
} }
+4 -3
View File
@@ -1,7 +1,8 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class FocusedSynthesisCombo : BaseComboAction<Observe, FocusedSynthesis> internal sealed class FocusedSynthesisCombo() : BaseComboAction<Observe, FocusedSynthesis>(
ActionType.Observe, ActionType.FocusedSynthesis
)
{ {
public override ActionType ActionTypeA => ActionType.Observe;
public override ActionType ActionTypeB => ActionType.FocusedSynthesis;
} }
+9 -29
View File
@@ -1,33 +1,13 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class FocusedTouch : BaseAction internal sealed class FocusedTouch() : BaseAction(
ActionCategory.Quality, 68, 100243,
increasesQuality: true,
defaultCPCost: 18,
defaultEfficiency: 150,
defaultSuccessRate: 0.50f
)
{ {
public int CP = 18; public override float SuccessRate(Simulator s) =>
public int Eff = 150; s.ActionStates.Observed ? 1.00f : 0.50f;
public float SuccessNormal = 0.50f;
public float SuccessObserved = 1.00f;
public FocusedTouch()
{
Category = ActionCategory.Quality;
Level = 68;
ActionId = 100243;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = Eff;
}
public override void SuccessRate(Simulator s, ref float success)
{
success = s.ActionStates.Observed ? SuccessObserved : SuccessNormal;
}
} }
+4 -3
View File
@@ -1,7 +1,8 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class FocusedTouchCombo : BaseComboAction<Observe, FocusedTouch> internal sealed class FocusedTouchCombo() : BaseComboAction<Observe, FocusedTouch>(
ActionType.Observe, ActionType.FocusedTouch
)
{ {
public override ActionType ActionTypeA => ActionType.Observe;
public override ActionType ActionTypeB => ActionType.FocusedTouch;
} }
+5 -15
View File
@@ -1,20 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class GreatStrides : BaseBuffAction internal sealed class GreatStrides() : BaseBuffAction(
ActionCategory.Buffs, 21, 260,
EffectType.GreatStrides, duration: 3,
increasesStepCount: false,
defaultCPCost: 32)
{ {
public int CP = 32;
public GreatStrides()
{
Category = ActionCategory.Buffs;
Level = 21;
ActionId = 260;
Effect = EffectType.GreatStrides;
Duration = 3;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = CP;
}
} }
+10 -17
View File
@@ -1,26 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Groundwork : BaseAction internal sealed class Groundwork() : BaseAction(
ActionCategory.Synthesis, 72, 100403,
increasesProgress: true,
durabilityCost: 20,
defaultCPCost: 18,
defaultEfficiency: 300
)
{ {
public Groundwork() public override int Efficiency(Simulator s)
{
Category = ActionCategory.Synthesis;
Level = 72;
ActionId = 100403;
IncreasesProgress = true;
DurabilityCost = 20;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 18;
}
public override void Efficiency(Simulator s, ref int eff)
{ {
// Groundwork Mastery Trait // Groundwork Mastery Trait
eff = s.Input.Stats.Level >= 86 ? 360 : 300; var eff = s.Input.Stats.Level >= 86 ? 360 : 300;
if (s.Durability < s.CalculateDurabilityCost(DurabilityCost)) if (s.Durability < s.CalculateDurabilityCost(DurabilityCost))
eff /= 2; eff /= 2;
return eff;
} }
} }
+7 -22
View File
@@ -1,27 +1,12 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class HastyTouch : BaseAction internal sealed class HastyTouch() : BaseAction(
ActionCategory.Quality, 9, 100355,
increasesQuality: true,
defaultCPCost: 0,
defaultEfficiency: 100,
defaultSuccessRate: 0.60f
)
{ {
public HastyTouch()
{
Category = ActionCategory.Quality;
Level = 9;
ActionId = 100355;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 0;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 100;
}
public override void SuccessRate(Simulator s, ref float success)
{
success = 0.60f;
}
} }
+8 -17
View File
@@ -1,26 +1,17 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class HeartAndSoul : BaseBuffAction internal sealed class HeartAndSoul() : BaseBuffAction(
ActionCategory.Other, 86, 100419,
EffectType.HeartAndSoul, duration: 1,
macroWaitTime: 3,
increasesStepCount: false
)
{ {
public HeartAndSoul()
{
Level = 86;
Effect = EffectType.HeartAndSoul;
MacroWaitTime = 3;
ActionId = 100419;
Category = ActionCategory.Other;
IncreasesStepCount = false;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 0;
}
public override bool IsPossible(Simulator s) => public override bool IsPossible(Simulator s) =>
base.IsPossible(s) && s.Input.Stats.IsSpecialist && !s.ActionStates.UsedHeartAndSoul; base.IsPossible(s) && s.Input.Stats.IsSpecialist && !s.ActionStates.UsedHeartAndSoul;
public override bool CouldUse(Simulator s, ref int cost) => !s.ActionStates.UsedHeartAndSoul; public override bool CouldUse(Simulator s) =>
!s.ActionStates.UsedHeartAndSoul;
public override string GetTooltip(Simulator s, bool addUsability) => public override string GetTooltip(Simulator s, bool addUsability) =>
$"{GetBaseTooltip(s, addUsability)}Specialist Only\n"; $"{GetBaseTooltip(s, addUsability)}Specialist Only\n";
+4 -14
View File
@@ -1,19 +1,9 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Innovation : BaseBuffAction internal sealed class Innovation() : BaseBuffAction(
ActionCategory.Buffs, 26, 19004,
EffectType.Innovation, duration: 4,
defaultCPCost: 18)
{ {
public Innovation()
{
Level = 26;
Effect = EffectType.Innovation;
MacroWaitTime = 3;
ActionId = 19004;
Category = ActionCategory.Buffs;
Duration = 4;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 18;
}
} }
+10 -23
View File
@@ -1,32 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class IntensiveSynthesis : BaseAction internal sealed class IntensiveSynthesis() : BaseAction(
ActionCategory.Synthesis, 78, 100315,
increasesProgress: true,
defaultCPCost: 6,
defaultEfficiency: 400
)
{ {
public IntensiveSynthesis() public override bool CouldUse(Simulator s) =>
{
Category = ActionCategory.Synthesis;
Level = 78;
ActionId = 100315;
IncreasesProgress = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 6;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 400;
}
public override bool CouldUse(Simulator s, ref int cost) =>
(s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul)) (s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul))
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
public override void UseSuccess(Simulator s, ref int eff) public override void UseSuccess(Simulator s)
{ {
base.UseSuccess(s, ref eff); base.UseSuccess(s);
if (s.Condition != Condition.Good && s.Condition != Condition.Excellent) if (s.Condition != Condition.Good && s.Condition != Condition.Excellent)
s.RemoveEffect(EffectType.HeartAndSoul); s.RemoveEffect(EffectType.HeartAndSoul);
} }
+7 -19
View File
@@ -1,30 +1,18 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Manipulation : BaseBuffAction internal sealed class Manipulation() : BaseBuffAction(
ActionCategory.Durability, 65, 4574,
EffectType.Manipulation, duration: 8,
defaultCPCost: 96)
{ {
public Manipulation()
{
Category = ActionCategory.Durability;
Level = 65;
ActionId = 4574;
Effect = EffectType.Manipulation;
Duration = 8;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 96;
}
public override bool IsPossible(Simulator s) => public override bool IsPossible(Simulator s) =>
s.Input.Stats.CanUseManipulation && base.IsPossible(s); s.Input.Stats.CanUseManipulation && base.IsPossible(s);
public override void Use(Simulator s, ref int cost, ref float success, ref int eff) public override void Use(Simulator s)
{ {
UseSuccess(s, ref eff); UseSuccess(s);
CPCost(s, ref cost);
s.ReduceCP(cost); s.ReduceCP(CPCost(s));
s.IncreaseStepCount(); s.IncreaseStepCount();
+6 -15
View File
@@ -1,20 +1,11 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class MastersMend : BaseAction internal sealed class MastersMend() : BaseAction(
ActionCategory.Durability, 7, 100003,
durabilityCost: 0,
defaultCPCost: 88
)
{ {
public MastersMend() public override void UseSuccess(Simulator s) =>
{
Category = ActionCategory.Durability;
Level = 7;
ActionId = 100003;
DurabilityCost = 0;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 88;
}
public override void UseSuccess(Simulator s, ref int eff) =>
s.RestoreDurability(30); s.RestoreDurability(30);
} }
+9 -22
View File
@@ -1,32 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class MuscleMemory : BaseAction internal sealed class MuscleMemory() : BaseAction(
ActionCategory.FirstTurn, 54, 100379,
increasesProgress: true,
defaultCPCost: 6,
defaultEfficiency: 300
)
{ {
public MuscleMemory()
{
Category = ActionCategory.FirstTurn;
Level = 54;
ActionId = 100379;
IncreasesProgress = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 6;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 300;
}
public override bool IsPossible(Simulator s) => s.IsFirstStep && base.IsPossible(s); public override bool IsPossible(Simulator s) => s.IsFirstStep && base.IsPossible(s);
public override bool CouldUse(Simulator s, ref int cost) => s.IsFirstStep && base.CouldUse(s, ref cost); public override bool CouldUse(Simulator s) => s.IsFirstStep && base.CouldUse(s);
public override void UseSuccess(Simulator s, ref int eff) public override void UseSuccess(Simulator s)
{ {
base.UseSuccess(s, ref eff); base.UseSuccess(s);
s.AddEffect(EffectType.MuscleMemory, 5); s.AddEffect(EffectType.MuscleMemory, 5);
} }
} }
+5 -12
View File
@@ -1,17 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Observe : BaseAction internal sealed class Observe() : BaseAction(
ActionCategory.Other, 13, 100010,
durabilityCost: 0,
defaultCPCost: 7
)
{ {
public Observe()
{
Category = ActionCategory.Other;
Level = 13;
ActionId = 100010;
DurabilityCost = 0;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 7;
}
} }
+10 -23
View File
@@ -1,32 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class PreciseTouch : BaseAction internal sealed class PreciseTouch() : BaseAction(
ActionCategory.Quality, 53, 100128,
increasesQuality: true,
defaultCPCost: 18,
defaultEfficiency: 150
)
{ {
public PreciseTouch() public override bool CouldUse(Simulator s) =>
{
Category = ActionCategory.Quality;
Level = 53;
ActionId = 100128;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 18;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 150;
}
public override bool CouldUse(Simulator s, ref int cost) =>
(s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul)) (s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul))
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
public override void UseSuccess(Simulator s, ref int eff) public override void UseSuccess(Simulator s)
{ {
base.UseSuccess(s, ref eff); base.UseSuccess(s);
s.StrengthenEffect(EffectType.InnerQuiet); s.StrengthenEffect(EffectType.InnerQuiet);
if (s.Condition != Condition.Good && s.Condition != Condition.Excellent) if (s.Condition != Condition.Good && s.Condition != Condition.Excellent)
s.RemoveEffect(EffectType.HeartAndSoul); s.RemoveEffect(EffectType.HeartAndSoul);
+8 -22
View File
@@ -1,29 +1,15 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class PreparatoryTouch : BaseAction internal sealed class PreparatoryTouch() : BaseAction(
ActionCategory.Quality, 71, 100299,
increasesQuality: true,
durabilityCost: 20,
defaultCPCost: 40,
defaultEfficiency: 200)
{ {
public PreparatoryTouch() public override void UseSuccess(Simulator s)
{ {
Category = ActionCategory.Quality; base.UseSuccess(s);
Level = 71;
ActionId = 100299;
IncreasesQuality = true;
DurabilityCost = 20;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 40;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 200;
}
public override void UseSuccess(Simulator s, ref int eff)
{
base.UseSuccess(s, ref eff);
s.StrengthenEffect(EffectType.InnerQuiet); s.StrengthenEffect(EffectType.InnerQuiet);
} }
} }
+9 -23
View File
@@ -1,28 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class PrudentSynthesis : BaseAction internal sealed class PrudentSynthesis() : BaseAction(
ActionCategory.Synthesis, 88, 100427,
increasesProgress: true,
durabilityCost: 5,
defaultCPCost: 18,
defaultEfficiency: 180
)
{ {
public override bool CouldUse(Simulator s) =>
public PrudentSynthesis()
{
Category = ActionCategory.Synthesis;
Level = 88;
ActionId = 100427;
IncreasesProgress = true;
DurabilityCost /= 2;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 18;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 180;
}
public override bool CouldUse(Simulator s, ref int cost) =>
!(s.HasEffect(EffectType.WasteNot) || s.HasEffect(EffectType.WasteNot2)) !(s.HasEffect(EffectType.WasteNot) || s.HasEffect(EffectType.WasteNot2))
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
} }
+9 -22
View File
@@ -1,27 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class PrudentTouch : BaseAction internal sealed class PrudentTouch() : BaseAction(
ActionCategory.Quality, 66, 100227,
increasesQuality: true,
durabilityCost: 5,
defaultCPCost: 25,
defaultEfficiency: 100
)
{ {
public PrudentTouch() public override bool CouldUse(Simulator s) =>
{
Category = ActionCategory.Quality;
Level = 66;
ActionId = 100227;
IncreasesQuality = true;
DurabilityCost /= 2;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 25;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 100;
}
public override bool CouldUse(Simulator s, ref int cost) =>
!(s.HasEffect(EffectType.WasteNot) || s.HasEffect(EffectType.WasteNot2)) !(s.HasEffect(EffectType.WasteNot) || s.HasEffect(EffectType.WasteNot2))
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
} }
+9 -23
View File
@@ -1,28 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class RapidSynthesis : BaseAction internal sealed class RapidSynthesis() : BaseAction(
ActionCategory.Synthesis, 9, 100363,
increasesProgress: true,
defaultCPCost: 0,
defaultEfficiency: 250,
defaultSuccessRate: 0.50f
)
{ {
public RapidSynthesis()
{
Category = ActionCategory.Synthesis;
Level = 9;
ActionId = 100363;
IncreasesProgress = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 0;
}
// Rapid Synthesis Mastery Trait // Rapid Synthesis Mastery Trait
public override void Efficiency(Simulator s, ref int eff) public override int Efficiency(Simulator s) =>
{ s.Input.Stats.Level >= 63 ? 500 : 250;
eff = s.Input.Stats.Level >= 63 ? 500 : 250;
}
public override void SuccessRate(Simulator s, ref float success)
{
success = 0.50f;
}
} }
+9 -22
View File
@@ -1,32 +1,19 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Reflect : BaseAction internal sealed class Reflect() : BaseAction(
ActionCategory.FirstTurn, 69, 100387,
increasesQuality: true,
defaultCPCost: 6,
defaultEfficiency: 100
)
{ {
public Reflect()
{
Category = ActionCategory.FirstTurn;
Level = 69;
ActionId = 100387;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 6;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 100;
}
public override bool IsPossible(Simulator s) => s.IsFirstStep && base.IsPossible(s); public override bool IsPossible(Simulator s) => s.IsFirstStep && base.IsPossible(s);
public override bool CouldUse(Simulator s, ref int cost) => s.IsFirstStep && base.CouldUse(s, ref cost); public override bool CouldUse(Simulator s) => s.IsFirstStep && base.CouldUse(s);
public override void UseSuccess(Simulator s, ref int eff) public override void UseSuccess(Simulator s)
{ {
base.UseSuccess(s, ref eff); base.UseSuccess(s);
s.StrengthenEffect(EffectType.InnerQuiet); s.StrengthenEffect(EffectType.InnerQuiet);
} }
} }
+8 -18
View File
@@ -1,22 +1,12 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class StandardTouch : BaseAction internal sealed class StandardTouch() : BaseAction(
ActionCategory.Quality, 18, 100004,
increasesQuality: true,
defaultCPCost: 32,
defaultEfficiency: 125
)
{ {
public StandardTouch() public override int CPCost(Simulator s) =>
{ s.ActionStates.TouchComboIdx == 1 ? 18 : 32;
Category = ActionCategory.Quality;
Level = 18;
ActionId = 100004;
IncreasesQuality = true;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = s.ActionStates.TouchComboIdx == 1 ? 18 : 32;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 125;
}
} }
+4 -3
View File
@@ -1,7 +1,8 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class StandardTouchCombo : BaseComboAction<BasicTouch, StandardTouch> internal sealed class StandardTouchCombo() : BaseComboAction<BasicTouch, StandardTouch>(
ActionType.BasicTouch, ActionType.StandardTouch, 18 * 2
)
{ {
public override ActionType ActionTypeA => ActionType.BasicTouch;
public override ActionType ActionTypeB => ActionType.StandardTouch;
} }
+13 -20
View File
@@ -1,28 +1,21 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class TrainedEye : BaseAction internal sealed class TrainedEye() : BaseAction(
ActionCategory.FirstTurn, 80, 100283,
increasesQuality: true,
defaultCPCost: 250
)
{ {
public TrainedEye() public override bool IsPossible(Simulator s) =>
{ s.IsFirstStep &&
Category = ActionCategory.FirstTurn; !s.Input.Recipe.IsExpert &&
Level = 80; s.Input.Stats.Level >= (s.Input.Recipe.ClassJobLevel + 10) &&
ActionId = 100283; base.IsPossible(s);
IncreasesQuality = true;
}
public override void CPCost(Simulator s,ref int cost) public override bool CouldUse(Simulator s) =>
{ s.IsFirstStep && base.CouldUse(s);
cost = 250;
}
public override bool IsPossible(Simulator s) => s.IsFirstStep && public override void UseSuccess(Simulator s) =>
!s.Input.Recipe.IsExpert &&
s.Input.Stats.Level >= (s.Input.Recipe.ClassJobLevel + 10) &&
base.IsPossible(s);
public override bool CouldUse(Simulator s, ref int cost) => s.IsFirstStep && base.CouldUse(s, ref cost);
public override void UseSuccess(Simulator s, ref int eff) =>
s.IncreaseQualityRaw(s.Input.Recipe.MaxQuality - s.Quality); s.IncreaseQualityRaw(s.Input.Recipe.MaxQuality - s.Quality);
public override string GetTooltip(Simulator s, bool addUsability) => public override string GetTooltip(Simulator s, bool addUsability) =>
+9 -22
View File
@@ -1,27 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class TrainedFinesse : BaseAction internal sealed class TrainedFinesse() : BaseAction(
ActionCategory.Quality, 90, 100435,
increasesQuality: true,
durabilityCost: 0,
defaultCPCost: 32,
defaultEfficiency: 100
)
{ {
public TrainedFinesse() public override bool CouldUse(Simulator s) =>
{
Category = ActionCategory.Quality;
Level = 90;
ActionId = 100435;
IncreasesQuality = true;
DurabilityCost = 0;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 32;
}
public override void Efficiency(Simulator s, ref int eff)
{
eff = 100;
}
public override bool CouldUse(Simulator s, ref int cost) =>
s.GetEffectStrength(EffectType.InnerQuiet) == 10 s.GetEffectStrength(EffectType.InnerQuiet) == 10
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
} }
+8 -17
View File
@@ -1,25 +1,16 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class TricksOfTheTrade : BaseAction internal sealed class TricksOfTheTrade() : BaseAction(
ActionCategory.Other, 13, 100371,
durabilityCost: 0,
defaultCPCost: 0
)
{ {
public TricksOfTheTrade() public override bool CouldUse(Simulator s) =>
{
Category = ActionCategory.Other;
Level = 13;
ActionId = 100371;
DurabilityCost = 0;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 0;
}
public override bool CouldUse(Simulator s, ref int cost) =>
(s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul)) (s.Condition == Condition.Good || s.Condition == Condition.Excellent || s.HasEffect(EffectType.HeartAndSoul))
&& base.CouldUse(s, ref cost); && base.CouldUse(s);
public override void UseSuccess(Simulator s, ref int eff) public override void UseSuccess(Simulator s)
{ {
s.RestoreCP(20); s.RestoreCP(20);
if (s.Condition != Condition.Good && s.Condition != Condition.Excellent) if (s.Condition != Condition.Good && s.Condition != Condition.Excellent)
+5 -13
View File
@@ -1,18 +1,10 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class Veneration : BaseBuffAction internal sealed class Veneration() : BaseBuffAction(
ActionCategory.Buffs, 15, 19297,
EffectType.Veneration, duration: 4,
defaultCPCost: 18
)
{ {
public Veneration()
{
Category = ActionCategory.Buffs;
Level = 15;
ActionId = 19297;
Effect = EffectType.Veneration;
Duration = 4;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 18;
}
} }
+7 -17
View File
@@ -1,24 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class WasteNot : BaseBuffAction internal sealed class WasteNot() : BaseBuffAction(
ActionCategory.Durability, 15, 4631,
EffectType.WasteNot, duration: 4,
defaultCPCost: 56
)
{ {
public WasteNot() public override void UseSuccess(Simulator s)
{ {
Category = ActionCategory.Durability; base.UseSuccess(s);
Level = 15;
ActionId = 4631;
Effect = EffectType.WasteNot;
Duration = 4;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 56;
}
public override void UseSuccess(Simulator s, ref int eff)
{
base.UseSuccess(s, ref eff);
s.RemoveEffect(EffectType.WasteNot2); s.RemoveEffect(EffectType.WasteNot2);
} }
} }
+7 -17
View File
@@ -1,24 +1,14 @@
namespace Craftimizer.Simulator.Actions; namespace Craftimizer.Simulator.Actions;
internal sealed class WasteNot2 : BaseBuffAction internal sealed class WasteNot2() : BaseBuffAction(
ActionCategory.Durability, 47, 4639,
EffectType.WasteNot2, duration: 8,
defaultCPCost: 98
)
{ {
public WasteNot2() public override void UseSuccess(Simulator s)
{ {
Category = ActionCategory.Durability; base.UseSuccess(s);
Level = 47;
ActionId = 4639;
Effect = EffectType.WasteNot2;
Duration = 8;
}
public override void CPCost(Simulator s, ref int cost)
{
cost = 98;
}
public override void UseSuccess(Simulator s, ref int eff)
{
base.UseSuccess(s, ref eff);
s.RemoveEffect(EffectType.WasteNot); s.RemoveEffect(EffectType.WasteNot);
} }
} }
+1
View File
@@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
+4 -8
View File
@@ -21,10 +21,6 @@ public class Simulator
public ref Effects ActiveEffects => ref state.ActiveEffects; public ref Effects ActiveEffects => ref state.ActiveEffects;
public ref ActionStates ActionStates => ref state.ActionStates; public ref ActionStates ActionStates => ref state.ActionStates;
private int cost;
private int eff;
private float success;
public bool IsFirstStep => state.StepCount == 0; public bool IsFirstStep => state.StepCount == 0;
public virtual CompletionState CompletionState { public virtual CompletionState CompletionState {
@@ -54,7 +50,7 @@ public class Simulator
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ExecuteUnchecked(ActionType action) => private void ExecuteUnchecked(ActionType action) =>
action.Base().Use(this, ref cost, ref success, ref eff); action.Base().Use(this);
private ActionResponse Execute(ActionType action) private ActionResponse Execute(ActionType action)
{ {
@@ -62,7 +58,7 @@ public class Simulator
return ActionResponse.SimulationComplete; return ActionResponse.SimulationComplete;
var baseAction = action.Base(); var baseAction = action.Base();
if (!baseAction.CanUse(this, ref cost)) if (!baseAction.CanUse(this))
{ {
if (baseAction.Level > Input.Stats.Level) if (baseAction.Level > Input.Stats.Level)
return ActionResponse.ActionNotUnlocked; return ActionResponse.ActionNotUnlocked;
@@ -70,12 +66,12 @@ public class Simulator
return ActionResponse.ActionNotUnlocked; return ActionResponse.ActionNotUnlocked;
if (action is ActionType.CarefulObservation or ActionType.HeartAndSoul && !Input.Stats.IsSpecialist) if (action is ActionType.CarefulObservation or ActionType.HeartAndSoul && !Input.Stats.IsSpecialist)
return ActionResponse.ActionNotUnlocked; return ActionResponse.ActionNotUnlocked;
if (cost > CP) if (baseAction.CPCost(this) > CP)
return ActionResponse.NotEnoughCP; return ActionResponse.NotEnoughCP;
return ActionResponse.CannotUseAction; return ActionResponse.CannotUseAction;
} }
baseAction.Use(this, ref cost, ref success, ref eff); baseAction.Use(this);
return ActionResponse.UsedAction; return ActionResponse.UsedAction;
} }
+12 -2
View File
@@ -34,13 +34,22 @@ internal static class Intrinsics
return m; return m;
} }
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<float> ClearLastN(Vector256<float> data, int len)
{
var threshold = Vector256.Create<int>(len);
var index = Vector256.Create(0, 1, 2, 3, 4, 5, 6, 7);
return Avx.And(Avx2.CompareGreaterThan(threshold, index).AsSingle(), data);
}
[Pure] [Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
// https://stackoverflow.com/a/23592221 // https://stackoverflow.com/a/23592221
private static int HMaxIndexAVX2(Vector<float> v, int len) private static int HMaxIndexAVX2(Vector<float> v, int len)
{ {
// Remove NaNs // Remove NaNs
var vfilt = Avx.Blend(v.AsVector256(), Vector256<float>.Zero, (byte)~((1 << len) - 1)); var vfilt = ClearLastN(v.AsVector256(), len);
// Find max value and broadcast to all lanes // Find max value and broadcast to all lanes
var vmax128 = HMax(vfilt); var vmax128 = HMax(vfilt);
@@ -50,7 +59,7 @@ internal static class Intrinsics
var vcmp = Avx.CompareEqual(vfilt, vmax); var vcmp = Avx.CompareEqual(vfilt, vmax);
var mask = unchecked((uint)Avx2.MoveMask(vcmp.AsByte())); var mask = unchecked((uint)Avx2.MoveMask(vcmp.AsByte()));
var inverseIdx = BitOperations.LeadingZeroCount(mask << (8 - len << 2)) >> 2; var inverseIdx = BitOperations.LeadingZeroCount(mask << ((8 - len) << 2)) >> 2;
return len - 1 - inverseIdx; return len - 1 - inverseIdx;
} }
@@ -158,6 +167,7 @@ internal static class Intrinsics
[Pure] [Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
[SkipLocalsInit]
public static Vector<float> ReciprocalSqrt(Vector<float> data) public static Vector<float> ReciprocalSqrt(Vector<float> data)
{ {
if (Avx.IsSupported && Vector<float>.Count >= Vector256<float>.Count) if (Avx.IsSupported && Vector<float>.Count >= Vector256<float>.Count)
+4 -8
View File
@@ -41,10 +41,7 @@ internal sealed class Simulator : SimulatorNoRandom
private bool CouldUseAction(ActionType action, BaseAction baseAction, bool strict) private bool CouldUseAction(ActionType action, BaseAction baseAction, bool strict)
#pragma warning restore MA0051 // Method is too long #pragma warning restore MA0051 // Method is too long
{ {
var success = 0f; if (CalculateSuccessRate(baseAction.SuccessRate(this)) != 1)
int cost = 0, eff = 0;
baseAction.SuccessRate(this, ref success);
if (Math.Abs(CalculateSuccessRate(success) - 1) > float.Epsilon)
return false; return false;
// don't allow quality moves at max quality // don't allow quality moves at max quality
@@ -55,7 +52,7 @@ internal sealed class Simulator : SimulatorNoRandom
{ {
// always use Trained Eye if it's available // always use Trained Eye if it's available
if (action == ActionType.TrainedEye) if (action == ActionType.TrainedEye)
return baseAction.CouldUse(this, ref cost); return baseAction.CouldUse(this);
// don't allow quality moves under Muscle Memory for difficult crafts // don't allow quality moves under Muscle Memory for difficult crafts
if (Input.Recipe.ClassJobLevel == 90 && if (Input.Recipe.ClassJobLevel == 90 &&
@@ -88,8 +85,7 @@ internal sealed class Simulator : SimulatorNoRandom
if (baseAction.IncreasesProgress) if (baseAction.IncreasesProgress)
{ {
baseAction.Efficiency(this, ref eff); var progressIncrease = CalculateProgressGain(baseAction.Efficiency(this));
var progressIncrease = CalculateProgressGain(eff);
var wouldFinish = Progress + progressIncrease >= Input.Recipe.MaxProgress; var wouldFinish = Progress + progressIncrease >= Input.Recipe.MaxProgress;
if (wouldFinish) if (wouldFinish)
@@ -133,7 +129,7 @@ internal sealed class Simulator : SimulatorNoRandom
return false; return false;
} }
return baseAction.CouldUse(this, ref cost); return baseAction.CouldUse(this);
} }
// https://github.com/alostsock/crafty/blob/cffbd0cad8bab3cef9f52a3e3d5da4f5e3781842/crafty/src/craft_state.rs#L137 // https://github.com/alostsock/crafty/blob/cffbd0cad8bab3cef9f52a3e3d5da4f5e3781842/crafty/src/craft_state.rs#L137
+1 -2
View File
@@ -170,8 +170,7 @@ public class SimulatorTests
}, },
0, 4064, 15, 332); 0, 4064, 15, 332);
Assert.AreEqual(10, state.ActiveEffects.InnerQuiet); Assert.AreEqual(10, state.ActiveEffects.InnerQuiet);
var cost = 0; Assert.IsTrue(ActionType.TrainedFinesse.Base().CanUse(new SimulatorNoRandom() { State = state }));
Assert.IsTrue(ActionType.TrainedFinesse.Base().CanUse(new SimulatorNoRandom() { State = state }, ref cost));
} }
[TestMethod] [TestMethod]