Refactor ui code, add temp synth window

This commit is contained in:
Asriel Camora
2023-07-17 00:13:59 +04:00
parent 858d5d468c
commit c8231b5d2a
11 changed files with 288 additions and 132 deletions
+5 -5
View File
@@ -1,7 +1,5 @@
using Craftimizer.Plugin.Windows; using Craftimizer.Plugin.Windows;
using Craftimizer.Simulator; using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using Dalamud.Game.Command;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
@@ -15,9 +13,10 @@ public sealed class Plugin : IDalamudPlugin
public string Name => "Craftimizer"; public string Name => "Craftimizer";
public WindowSystem WindowSystem { get; } public WindowSystem WindowSystem { get; }
public SettingsWindow SettingsWindow { get; } public Settings SettingsWindow { get; }
public CraftingLog RecipeNoteWindow { get; } public CraftingLog RecipeNoteWindow { get; }
public SimulatorWindow? SimulatorWindow { get; set; } public Craft SynthesisWindow { get; }
public Windows.Simulator? SimulatorWindow { get; set; }
public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface) public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface)
{ {
@@ -27,8 +26,9 @@ public sealed class Plugin : IDalamudPlugin
WindowSystem = new(Name); WindowSystem = new(Name);
RecipeNoteWindow = new();
SettingsWindow = new(); SettingsWindow = new();
RecipeNoteWindow = new();
SynthesisWindow = new();
Service.PluginInterface.UiBuilder.Draw += WindowSystem.Draw; Service.PluginInterface.UiBuilder.Draw += WindowSystem.Draw;
Service.PluginInterface.UiBuilder.OpenConfigUi += OpenSettingsWindow; Service.PluginInterface.UiBuilder.OpenConfigUi += OpenSettingsWindow;
+20 -7
View File
@@ -1,6 +1,7 @@
using Craftimizer.Simulator; using Craftimizer.Simulator;
using Dalamud.Utility; using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using System; using System;
@@ -83,21 +84,33 @@ internal static unsafe class Gearsets
public static GearsetStats CalculateGearsetStats(GearsetItem[] gearsetItems) => public static GearsetStats CalculateGearsetStats(GearsetItem[] gearsetItems) =>
gearsetItems.Select(CalculateGearsetItemStats).Aggregate(BaseStats, (a, b) => new(a.CP + b.CP, a.Craftsmanship + b.Craftsmanship, a.Control + b.Control)); gearsetItems.Select(CalculateGearsetItemStats).Aggregate(BaseStats, (a, b) => new(a.CP + b.CP, a.Craftsmanship + b.Craftsmanship, a.Control + b.Control));
public static CharacterStats CalculateCharacterStats(GearsetItem[] gearsetItems, int characterLevel, bool canUseManipulation) public static GearsetStats CalculateGearsetCurrentStats()
{ {
var stats = CalculateGearsetStats(gearsetItems); var attributes = UIState.Instance()->PlayerState.Attributes;
return new CharacterStats
return new()
{ {
CP = stats.CP, CP = attributes[ParamCP],
Craftsmanship = stats.Craftsmanship, Craftsmanship = attributes[ParamCraftsmanship],
Control = stats.Control, Control = attributes[ParamControl],
};
}
public static CharacterStats CalculateCharacterStats(GearsetItem[] gearsetItems, int characterLevel, bool canUseManipulation) =>
CalculateCharacterStats(CalculateGearsetStats(gearsetItems), gearsetItems, characterLevel, canUseManipulation);
public static CharacterStats CalculateCharacterStats(GearsetStats gearsetStats, GearsetItem[] gearsetItems, int characterLevel, bool canUseManipulation) =>
new()
{
CP = gearsetStats.CP,
Craftsmanship = gearsetStats.Craftsmanship,
Control = gearsetStats.Control,
Level = characterLevel, Level = characterLevel,
CanUseManipulation = canUseManipulation, CanUseManipulation = canUseManipulation,
HasSplendorousBuff = gearsetItems.Any(IsSplendorousTool), HasSplendorousBuff = gearsetItems.Any(IsSplendorousTool),
IsSpecialist = gearsetItems.Any(IsSpecialistSoulCrystal), IsSpecialist = gearsetItems.Any(IsSpecialistSoulCrystal),
CLvl = CalculateCLvl(characterLevel), CLvl = CalculateCLvl(characterLevel),
}; };
}
public static bool IsItem(GearsetItem item, uint itemId) => public static bool IsItem(GearsetItem item, uint itemId) =>
item.itemId == itemId; item.itemId == itemId;
+112
View File
@@ -0,0 +1,112 @@
using Craftimizer.Plugin;
using Craftimizer.Simulator;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.UI;
using Lumina.Excel.GeneratedSheets;
using System.Linq;
using System;
using ClassJob = Craftimizer.Simulator.ClassJob;
using CSRecipeNote = FFXIVClientStructs.FFXIV.Client.Game.UI.RecipeNote;
using ActionType = Craftimizer.Simulator.Actions.ActionType;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
namespace Craftimizer.Utils;
public unsafe class RecipeNote
{
public AddonRecipeNote* AddonRecipe { get; private set; }
public AddonSynthesis* AddonSynthesis { get; private set; }
public CSRecipeNote* State { get; private set; }
public ushort RecipeId { get; private set; }
public Recipe Recipe { get; private set; } = null!;
public RecipeLevelTable Table { get; private set; } = null!;
public RecipeInfo Info { get; private set; } = null!;
public ClassJob ClassJob { get; private set; }
public short CharacterLevel { get; private set; }
public bool CanUseManipulation { get; private set; }
public int HQIngredientCount { get; private set; }
public int MaxStartingQuality { get; private set; }
public RecipeNote()
{
}
public bool Update(out bool isNewRecipe)
{
isNewRecipe = false;
if (Service.ClientState.LocalPlayer == null)
return false;
AddonRecipe = (AddonRecipeNote*)Service.GameGui.GetAddonByName("RecipeNote");
AddonSynthesis = (AddonSynthesis*)Service.GameGui.GetAddonByName("Synthesis");
if (AddonRecipe == null)
return false;
if (AddonSynthesis == null)
return false;
State = CSRecipeNote.Instance();
var list = State->RecipeList;
if (list == null)
return false;
var recipeEntry = list->SelectedRecipe;
if (recipeEntry == null)
return false;
isNewRecipe = RecipeId != recipeEntry->RecipeId;
RecipeId = recipeEntry->RecipeId;
var recipe = LuminaSheets.RecipeSheet.GetRow(RecipeId);
if (recipe == null)
return false;
Recipe = recipe;
if (isNewRecipe)
CalculateStats();
return true;
}
private void CalculateStats()
{
Table = Recipe.RecipeLevelTable.Value!;
Info = CreateInfo();
ClassJob = (ClassJob)Recipe.CraftType.Row;
CharacterLevel = PlayerState.Instance()->ClassJobLevelArray[ClassJob.GetClassJobIndex()];
CanUseManipulation = ActionManager.CanUseActionOnTarget(ActionType.Manipulation.GetId(ClassJob), (GameObject*)Service.ClientState.LocalPlayer!.Address);
HQIngredientCount = Recipe.UnkData5
.Where(i =>
i != null &&
i.ItemIngredient != 0 &&
(LuminaSheets.ItemSheet.GetRow((uint)i.ItemIngredient)?.CanBeHq ?? false)
).Sum(i => i.AmountIngredient);
MaxStartingQuality = (int)Math.Floor(Recipe.MaterialQualityFactor * Info.MaxQuality / 100f);
}
private RecipeInfo CreateInfo() =>
new()
{
IsExpert = Recipe.IsExpert,
ClassJobLevel = Table.ClassJobLevel,
RLvl = (int)Table.RowId,
ConditionsFlag = Table.ConditionsFlag,
MaxDurability = Table.Durability * Recipe.DurabilityFactor / 100,
MaxQuality = (int)Table.Quality * Recipe.QualityFactor / 100,
MaxProgress = Table.Difficulty * Recipe.DifficultyFactor / 100,
QualityModifier = Table.QualityModifier,
QualityDivider = Table.QualityDivider,
ProgressModifier = Table.ProgressModifier,
ProgressDivider = Table.ProgressDivider,
};
}
+87
View File
@@ -0,0 +1,87 @@
using Craftimizer.Plugin.Utils;
using Craftimizer.Simulator;
using Craftimizer.Utils;
using Dalamud.Interface.Windowing;
using FFXIVClientStructs.FFXIV.Client.Game;
using ImGuiNET;
using System.Numerics;
namespace Craftimizer.Plugin.Windows;
public unsafe class Craft : Window
{
private const ImGuiWindowFlags WindowFlags = ImGuiWindowFlags.NoDecoration
| ImGuiWindowFlags.AlwaysAutoResize
| ImGuiWindowFlags.NoSavedSettings
| ImGuiWindowFlags.NoFocusOnAppearing
| ImGuiWindowFlags.NoNavFocus;
private RecipeNote RecipeUtils { get; } = new();
private bool WasOpen { get; set; }
private CharacterStats CharacterStats { get; set; } = null!;
public Craft() : base("Craftimizer SynthesisHelper", WindowFlags, true)
{
Service.WindowSystem.AddWindow(this);
IsOpen = true;
}
public override void Draw()
{
ImGui.Text($"{CharacterStats.CP};{CharacterStats.Control};{CharacterStats.Craftsmanship}");
}
public override void PreDraw()
{
var addon = RecipeUtils.AddonSynthesis;
ref var unit = ref addon->AtkUnitBase;
var scale = unit.Scale;
var pos = new Vector2(unit.X, unit.Y);
var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale;
var node = unit.GetNodeById(5);
Position = pos + new Vector2(size.X, node->Y * scale);
SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new(-1),
MaximumSize = new(10000, 10000)
};
base.PreDraw();
}
private bool DrawConditionsInner()
{
if (!RecipeUtils.Update(out _))
return false;
// Check if Synthesis addon is visible
if (RecipeUtils.AddonSynthesis->AtkUnitBase.WindowNode == null)
return false;
return base.DrawConditions();
}
public override bool DrawConditions()
{
var ret = DrawConditionsInner();
if (ret && !WasOpen)
ResetSimulation();
WasOpen = ret;
return ret;
}
private void ResetSimulation()
{
var container = InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems);
if (container == null)
return;
CharacterStats = Gearsets.CalculateCharacterStats(Gearsets.CalculateGearsetCurrentStats(), Gearsets.GetGearsetItems(container), RecipeUtils.CharacterLevel, RecipeUtils.CanUseManipulation);
}
}
+45 -101
View File
@@ -7,22 +7,18 @@ using Dalamud.Interface.Components;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Utility; using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Game.UI;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using ActionType = Craftimizer.Simulator.Actions.ActionType; using ActionType = Craftimizer.Simulator.Actions.ActionType;
using ClassJob = Craftimizer.Simulator.ClassJob; using RecipeNote = Craftimizer.Utils.RecipeNote;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
@@ -46,20 +42,7 @@ public unsafe class CraftingLog : Window
private static Food[] MedicineItems { get; } private static Food[] MedicineItems { get; }
private static Random Random { get; } private static Random Random { get; }
// Set in DrawConditions private RecipeNote RecipeUtils { get; } = new();
private AddonRecipeNote* Addon { get; set; }
private RecipeNote* State { get; set; }
private ushort RecipeId { get; set; }
private Recipe Recipe { get; set; } = null!;
// Set in CalculateRecipeStats (in DrawConditions)
private RecipeLevelTable RecipeTable { get; set; } = null!;
private RecipeInfo RecipeInfo { get; set; } = null!;
private ClassJob RecipeClassJob { get; set; }
private short RecipeCharacterLevel { get; set; }
private bool RecipeCanUseManipulation { get; set; }
private int RecipeHQIngredientCount { get; set; }
private int RecipeMaxStartingQuality { get; set; }
// Set in CalculateCharacterStats (in PreDraw) // Set in CalculateCharacterStats (in PreDraw)
private Gearsets.GearsetItem[] CharacterEquipment { get; set; } = null!; private Gearsets.GearsetItem[] CharacterEquipment { get; set; } = null!;
@@ -71,7 +54,10 @@ public unsafe class CraftingLog : Window
// Set in UI // Set in UI
private int QualityNotches { get; set; } private int QualityNotches { get; set; }
private int StartingQuality => RecipeHQIngredientCount == 0 ? 0 : (int)((float)QualityNotches * RecipeMaxStartingQuality / RecipeHQIngredientCount); private int StartingQuality =>
RecipeUtils.HQIngredientCount == 0 ?
0 :
(int)((float)QualityNotches * RecipeUtils.MaxStartingQuality / RecipeUtils.HQIngredientCount);
private Food? SelectedFood { get; set; } private Food? SelectedFood { get; set; }
private bool SelectedFoodHQ { get; set; } private bool SelectedFoodHQ { get; set; }
@@ -139,22 +125,6 @@ public unsafe class CraftingLog : Window
IsOpen = true; IsOpen = true;
} }
private void CalculateRecipeStats()
{
RecipeTable = Recipe.RecipeLevelTable.Value!;
RecipeInfo = CreateRecipeInfo(Recipe);
RecipeClassJob = (ClassJob)Recipe.CraftType.Row;
RecipeCharacterLevel = PlayerState.Instance()->ClassJobLevelArray[RecipeClassJob.GetClassJobIndex()];
RecipeCanUseManipulation = ActionManager.CanUseActionOnTarget(ActionType.Manipulation.GetId(RecipeClassJob), (GameObject*)Service.ClientState.LocalPlayer!.Address);
RecipeHQIngredientCount = Recipe.UnkData5
.Where(i =>
i != null &&
i.ItemIngredient != 0 &&
(LuminaSheets.ItemSheet.GetRow((uint)i.ItemIngredient)?.CanBeHq ?? false)
).Sum(i => i.AmountIngredient);
RecipeMaxStartingQuality = (int)Math.Floor(Recipe.MaterialQualityFactor * RecipeInfo.MaxQuality / 100f);
}
private void CalculateCharacterStats() private void CalculateCharacterStats()
{ {
var container = InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems); var container = InventoryManager.Instance()->GetInventoryContainer(InventoryType.EquippedItems);
@@ -162,7 +132,7 @@ public unsafe class CraftingLog : Window
return; return;
CharacterEquipment = Gearsets.GetGearsetItems(container); CharacterEquipment = Gearsets.GetGearsetItems(container);
CharacterStatsNoConsumable = Gearsets.CalculateCharacterStats(CharacterEquipment, RecipeCharacterLevel, RecipeCanUseManipulation); CharacterStatsNoConsumable = Gearsets.CalculateCharacterStats(CharacterEquipment, RecipeUtils.CharacterLevel, RecipeUtils.CanUseManipulation);
CharacterConsumableBonus = CalculateConsumableBonus(CharacterStatsNoConsumable); CharacterConsumableBonus = CalculateConsumableBonus(CharacterStatsNoConsumable);
CharacterStatsConsumable = CharacterStatsNoConsumable with CharacterStatsConsumable = CharacterStatsNoConsumable with
{ {
@@ -173,7 +143,7 @@ public unsafe class CraftingLog : Window
CharacterCannotCraftReason = Service.Configuration.OverrideUncraftability ? CannotCraftReason.OK : CanCraftRecipe(CharacterEquipment, CharacterStatsConsumable); CharacterCannotCraftReason = Service.Configuration.OverrideUncraftability ? CannotCraftReason.OK : CanCraftRecipe(CharacterEquipment, CharacterStatsConsumable);
if (CharacterCannotCraftReason == CannotCraftReason.OK) if (CharacterCannotCraftReason == CannotCraftReason.OK)
CharacterSimulationInput = new(CharacterStatsConsumable, RecipeInfo, StartingQuality, Random); CharacterSimulationInput = new(CharacterStatsConsumable, RecipeUtils.Info, StartingQuality, Random);
} }
public override void Draw() public override void Draw()
@@ -210,11 +180,11 @@ public unsafe class CraftingLog : Window
private void DrawRecipeInfo() private void DrawRecipeInfo()
{ {
var s = new StringBuilder(); var s = new StringBuilder();
s.AppendLine($"{RecipeClassJob.GetName()} {new string('★', RecipeTable.Stars)}"); s.AppendLine($"{RecipeUtils.ClassJob.GetName()} {new string('★', RecipeUtils.Table.Stars)}");
s.AppendLine($"Level {RecipeTable.ClassJobLevel} (RLvl {RecipeInfo.RLvl})"); s.AppendLine($"Level {RecipeUtils.Table.ClassJobLevel} (RLvl {RecipeUtils.Info.RLvl})");
s.AppendLine($"Durability: {RecipeInfo.MaxDurability}"); s.AppendLine($"Durability: {RecipeUtils.Info.MaxDurability}");
s.AppendLine($"Progress: {RecipeInfo.MaxProgress}"); s.AppendLine($"Progress: {RecipeUtils.Info.MaxProgress}");
s.AppendLine($"Quality: {RecipeInfo.MaxQuality}"); s.AppendLine($"Quality: {RecipeUtils.Info.MaxQuality}");
ImGui.Text(s.ToString()); ImGui.Text(s.ToString());
} }
@@ -231,10 +201,10 @@ public unsafe class CraftingLog : Window
private void DrawCraftParameters() private void DrawCraftParameters()
{ {
ImGui.BeginDisabled(RecipeHQIngredientCount == 0); ImGui.BeginDisabled(RecipeUtils.HQIngredientCount == 0);
var qualityNotches = QualityNotches; var qualityNotches = QualityNotches;
ImGui.SetNextItemWidth(LeftSideWidth - 115); ImGui.SetNextItemWidth(LeftSideWidth - 115);
if (ImGui.SliderInt("Starting Quality", ref qualityNotches, 0, RecipeHQIngredientCount, StartingQuality.ToString(), ImGuiSliderFlags.NoInput | ImGuiSliderFlags.AlwaysClamp)) if (ImGui.SliderInt("Starting Quality", ref qualityNotches, 0, RecipeUtils.HQIngredientCount, StartingQuality.ToString(), ImGuiSliderFlags.NoInput | ImGuiSliderFlags.AlwaysClamp))
QualityNotches = qualityNotches; QualityNotches = qualityNotches;
ImGui.EndDisabled(); ImGui.EndDisabled();
@@ -286,7 +256,7 @@ public unsafe class CraftingLog : Window
var height = fontSize + (padding.Y * 2); var height = fontSize + (padding.Y * 2);
var width = ImGui.GetContentRegionAvail().X; var width = ImGui.GetContentRegionAvail().X;
var size = new Vector2(width, height); var size = new Vector2(width, height);
var infoColWidth = SimulatorWindow.TooltipProgressBarSize.X; var infoColWidth = Simulator.TooltipProgressBarSize.X;
var infoButtonCount = 3; var infoButtonCount = 3;
var infoButtonWidth = (infoColWidth - ImGui.GetStyle().ItemSpacing.X * (infoButtonCount - 1)) / infoButtonCount; var infoButtonWidth = (infoColWidth - ImGui.GetStyle().ItemSpacing.X * (infoButtonCount - 1)) / infoButtonCount;
var infoButtonSize = new Vector2(infoButtonWidth, height); var infoButtonSize = new Vector2(infoButtonWidth, height);
@@ -319,7 +289,7 @@ public unsafe class CraftingLog : Window
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextWrapped(macro.Name); ImGui.TextWrapped(macro.Name);
if (state.HasValue) if (state.HasValue)
SimulatorWindow.DrawAllProgressTooltips(state!.Value); Simulator.DrawAllProgressTooltips(state!.Value);
if (ImGuiUtils.IconButtonSized(FontAwesomeIcon.Copy, infoButtonSize)) if (ImGuiUtils.IconButtonSized(FontAwesomeIcon.Copy, infoButtonSize))
CopyMacroToClipboard(macro); CopyMacroToClipboard(macro);
@@ -340,7 +310,7 @@ public unsafe class CraftingLog : Window
var j = 0; var j = 0;
foreach (var action in macro.Actions) foreach (var action in macro.Actions)
{ {
ImGui.Image(action.GetIcon(RecipeClassJob).ImGuiHandle, actionSize); ImGui.Image(action.GetIcon(RecipeUtils.ClassJob).ImGuiHandle, actionSize);
if (j++ % actionCount != actionCount - 1) if (j++ % actionCount != actionCount - 1)
ImGui.SameLine(); ImGui.SameLine();
if (j == actionCount * 2) if (j == actionCount * 2)
@@ -354,7 +324,7 @@ public unsafe class CraftingLog : Window
private void OpenSimulatorWindow(Macro? macro) private void OpenSimulatorWindow(Macro? macro)
{ {
Service.Plugin.OpenSimulatorWindow(Recipe.ItemResult.Value!, Recipe.IsExpert, CharacterSimulationInput, RecipeClassJob, macro); Service.Plugin.OpenSimulatorWindow(RecipeUtils.Recipe.ItemResult.Value!, RecipeUtils.Recipe.IsExpert, CharacterSimulationInput, RecipeUtils.ClassJob, macro);
} }
private string GetMacroCommand(ActionType action, bool addWaitTimes) private string GetMacroCommand(ActionType action, bool addWaitTimes)
@@ -363,9 +333,9 @@ public unsafe class CraftingLog : Window
if (actionBase is BaseComboAction comboActionBase) if (actionBase is BaseComboAction comboActionBase)
return $"{GetMacroCommand(comboActionBase.ActionTypeA, addWaitTimes)}\n{GetMacroCommand(comboActionBase.ActionTypeB, addWaitTimes)}"; return $"{GetMacroCommand(comboActionBase.ActionTypeA, addWaitTimes)}\n{GetMacroCommand(comboActionBase.ActionTypeB, addWaitTimes)}";
if (addWaitTimes) if (addWaitTimes)
return $"/ac \"{action.GetName(RecipeClassJob)}\" <wait.{actionBase.MacroWaitTime}>"; return $"/ac \"{action.GetName(RecipeUtils.ClassJob)}\" <wait.{actionBase.MacroWaitTime}>";
else else
return $"/ac \"{action.GetName(RecipeClassJob)}\""; return $"/ac \"{action.GetName(RecipeUtils.ClassJob)}\"";
} }
private void CopyMacroToClipboard(Macro macro) private void CopyMacroToClipboard(Macro macro)
@@ -401,11 +371,11 @@ public unsafe class CraftingLog : Window
if (!gearset->Flags.HasFlag(RaptureGearsetModule.GearsetFlag.Exists)) if (!gearset->Flags.HasFlag(RaptureGearsetModule.GearsetFlag.Exists))
continue; continue;
if (!ClassJobUtils.IsClassJob(gearset->ClassJob, RecipeClassJob)) if (!ClassJobUtils.IsClassJob(gearset->ClassJob, RecipeUtils.ClassJob))
continue; continue;
var items = Gearsets.GetGearsetItems(gearset); var items = Gearsets.GetGearsetItems(gearset);
var stats = Gearsets.CalculateCharacterStats(items, RecipeCharacterLevel, RecipeCanUseManipulation); var stats = Gearsets.CalculateCharacterStats(items, RecipeUtils.CharacterLevel, RecipeUtils.CanUseManipulation);
var gearsetId = gearset->ID + 1; var gearsetId = gearset->ID + 1;
ImGuiUtils.BeginGroupPanel($"{SafeMemory.ReadString((nint)gearset->Name, 47)} ({gearsetId})"); ImGuiUtils.BeginGroupPanel($"{SafeMemory.ReadString((nint)gearset->Name, 47)} ({gearsetId})");
@@ -421,61 +391,33 @@ public unsafe class CraftingLog : Window
public override bool DrawConditions() public override bool DrawConditions()
{ {
if (Service.ClientState.LocalPlayer == null) if (!RecipeUtils.Update(out var isNew))
return false; return false;
Addon = (AddonRecipeNote*)Service.GameGui.GetAddonByName("RecipeNote"); // Check if RecipeNote addon is visible
if (RecipeUtils.AddonRecipe->AtkUnitBase.WindowNode == null)
if (Addon == null)
return false; return false;
if (Addon->AtkUnitBase.WindowNode == null) // Check if RecipeNote has a visible selected recipe
if (!RecipeUtils.AddonRecipe->Unk258->IsVisible)
return false; return false;
State = RecipeNote.Instance(); if (isNew)
var list = State->RecipeList;
if (list == null)
return false;
var recipeEntry = list->SelectedRecipe;
if (recipeEntry == null)
return false;
var isNewRecipe = RecipeId != recipeEntry->RecipeId;
RecipeId = recipeEntry->RecipeId;
var recipe = LuminaSheets.RecipeSheet.GetRow(RecipeId);
if (recipe == null)
return false;
Recipe = recipe;
if (!Addon->Unk258->IsVisible)
return false;
if (isNewRecipe)
{
QualityNotches = 0; QualityNotches = 0;
CalculateRecipeStats();
}
return base.DrawConditions(); return base.DrawConditions();
} }
public override unsafe void PreDraw() public override unsafe void PreDraw()
{ {
ref var unit = ref Addon->AtkUnitBase; var addon = RecipeUtils.AddonRecipe;
ref var unit = ref addon->AtkUnitBase;
var scale = unit.Scale; var scale = unit.Scale;
var pos = new Vector2(unit.X, unit.Y); var pos = new Vector2(unit.X, unit.Y);
var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale; var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale;
var node = (AtkResNode*)Addon->Unk458; // unit.GetNodeById(59); var node = (AtkResNode*)addon->Unk458; // unit.GetNodeById(59);
var nodeParent = Addon->Unk258; // unit.GetNodeById(57); var nodeParent = addon->Unk258; // unit.GetNodeById(57);
Position = pos + new Vector2(size.X, (nodeParent->Y + node->Y) * scale); Position = pos + new Vector2(size.X, (nodeParent->Y + node->Y) * scale);
SizeConstraints = new WindowSizeConstraints SizeConstraints = new WindowSizeConstraints
@@ -537,36 +479,38 @@ public unsafe class CraftingLog : Window
private CannotCraftReason CanCraftRecipe(Gearsets.GearsetItem[] items, CharacterStats stats) private CannotCraftReason CanCraftRecipe(Gearsets.GearsetItem[] items, CharacterStats stats)
{ {
if (!ClassJobUtils.IsClassJob((byte)Service.ClientState.LocalPlayer!.ClassJob.Id, RecipeClassJob)) if (!ClassJobUtils.IsClassJob((byte)Service.ClientState.LocalPlayer!.ClassJob.Id, RecipeUtils.ClassJob))
return CannotCraftReason.WrongClassJob; return CannotCraftReason.WrongClassJob;
if (Recipe.IsSpecializationRequired && !stats.IsSpecialist) var recipe = RecipeUtils.Recipe;
if (recipe.IsSpecializationRequired && !stats.IsSpecialist)
return CannotCraftReason.SpecialistRequired; return CannotCraftReason.SpecialistRequired;
if (Recipe.ItemRequired.Row != 0) if (recipe.ItemRequired.Row != 0)
{ {
if (Recipe.ItemRequired.Value != null) if (recipe.ItemRequired.Value != null)
{ {
if (!items.Any(i => Gearsets.IsItem(i, Recipe.ItemRequired.Row))) if (!items.Any(i => Gearsets.IsItem(i, recipe.ItemRequired.Row)))
{ {
return CannotCraftReason.RequiredItem; return CannotCraftReason.RequiredItem;
} }
} }
} }
if (Recipe.StatusRequired.Row != 0) if (recipe.StatusRequired.Row != 0)
{ {
if (Recipe.StatusRequired.Value != null) if (recipe.StatusRequired.Value != null)
{ {
if (!Service.ClientState.LocalPlayer.StatusList.Any(s => s.StatusId == Recipe.StatusRequired.Row)) if (!Service.ClientState.LocalPlayer.StatusList.Any(s => s.StatusId == recipe.StatusRequired.Row))
return CannotCraftReason.RequiredStatus; return CannotCraftReason.RequiredStatus;
} }
} }
if (Recipe.RequiredCraftsmanship > stats.Craftsmanship) if (recipe.RequiredCraftsmanship > stats.Craftsmanship)
return CannotCraftReason.CraftsmanshipTooLow; return CannotCraftReason.CraftsmanshipTooLow;
if (Recipe.RequiredControl > stats.Control) if (recipe.RequiredControl > stats.Control)
return CannotCraftReason.ControlTooLow; return CannotCraftReason.ControlTooLow;
return CannotCraftReason.OK; return CannotCraftReason.OK;
@@ -6,11 +6,11 @@ using System;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public class SettingsWindow : Window public class Settings : Window
{ {
private static Configuration Config => Service.Configuration; private static Configuration Config => Service.Configuration;
public SettingsWindow() : base("Craftimizer Settings") public Settings() : base("Craftimizer Settings")
{ {
Service.WindowSystem.AddWindow(this); Service.WindowSystem.AddWindow(this);
@@ -9,7 +9,7 @@ using ClassJob = Craftimizer.Simulator.ClassJob;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public sealed partial class SimulatorWindow : Window, IDisposable public sealed partial class Simulator : Window, IDisposable
{ {
private const ImGuiWindowFlags WindowFlags = ImGuiWindowFlags.AlwaysAutoResize; private const ImGuiWindowFlags WindowFlags = ImGuiWindowFlags.AlwaysAutoResize;
@@ -23,13 +23,13 @@ public sealed partial class SimulatorWindow : Window, IDisposable
private string MacroName { get; set; } private string MacroName { get; set; }
// State is the state of the simulation *after* its corresponding action is executed. // State is the state of the simulation *after* its corresponding action is executed.
private List<(ActionType Action, string Tooltip, ActionResponse Response, SimulationState State)> Actions { get; } private List<(ActionType Action, string Tooltip, ActionResponse Response, SimulationState State)> Actions { get; }
private Simulator.Simulator Simulator { get; set; } private Craftimizer.Simulator.Simulator Sim { get; set; }
private SimulationState LatestState => Actions.Count == 0 ? new(Input) : Actions[^1].State; private SimulationState LatestState => Actions.Count == 0 ? new(Input) : Actions[^1].State;
// Simulator is set by ResetSimulator() // Simulator is set by ResetSimulator()
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public SimulatorWindow(Item item, bool isExpert, SimulationInput input, ClassJob classJob, Macro? macro) : base("Craftimizer Simulator", WindowFlags) public Simulator(Item item, bool isExpert, SimulationInput input, ClassJob classJob, Macro? macro) : base("Craftimizer Simulator", WindowFlags)
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{ {
Service.WindowSystem.AddWindow(this); Service.WindowSystem.AddWindow(this);
@@ -58,7 +58,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
private void ResetSimulator() private void ResetSimulator()
{ {
Simulator = Configuration.CreateSimulator(LatestState); Sim = Configuration.CreateSimulator(LatestState);
ReexecuteAllActions(); ReexecuteAllActions();
} }
} }
@@ -5,7 +5,7 @@ using System;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public sealed partial class SimulatorWindow : Window, IDisposable public sealed partial class Simulator : Window, IDisposable
{ {
private void AppendAction(ActionType action) private void AppendAction(ActionType action)
{ {
@@ -24,8 +24,8 @@ public sealed partial class SimulatorWindow : Window, IDisposable
} }
else else
{ {
var tooltip = actionBase.GetTooltip(Simulator, false); var tooltip = actionBase.GetTooltip(Sim, false);
var (response, state) = Simulator.Execute(LatestState, action); var (response, state) = Sim.Execute(LatestState, action);
Actions.Add((action, tooltip, response, state)); Actions.Add((action, tooltip, response, state));
} }
} }
@@ -13,7 +13,7 @@ using Dalamud.Game.Text;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public sealed partial class SimulatorWindow : Window, IDisposable public sealed partial class Simulator : Window, IDisposable
{ {
private const int ActionColumnSize = 260; private const int ActionColumnSize = 260;
@@ -36,7 +36,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
private static readonly (ActionCategory Category, ActionType[] Actions)[] SortedActions; private static readonly (ActionCategory Category, ActionType[] Actions)[] SortedActions;
static SimulatorWindow() static Simulator()
{ {
SortedActions = Enum.GetValues<ActionType>() SortedActions = Enum.GetValues<ActionType>()
.Where(a => a.Category() != ActionCategory.Combo) .Where(a => a.Category() != ActionCategory.Combo)
@@ -69,7 +69,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
Configuration.Save(); Configuration.Save();
} }
Simulator.SetState(LatestState); Sim.SetState(LatestState);
var actionSize = new Vector2((ActionColumnSize / 5) - ImGui.GetStyle().ItemSpacing.X * (6f / 5)); var actionSize = new Vector2((ActionColumnSize / 5) - ImGui.GetStyle().ItemSpacing.X * (6f / 5));
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero); ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
@@ -89,7 +89,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
if (cannotUse && Configuration.HideUnlearnedActions) if (cannotUse && Configuration.HideUnlearnedActions)
continue; continue;
var shouldNotUse = !baseAction.CanUse(Simulator) || Simulator.IsComplete; var shouldNotUse = !baseAction.CanUse(Sim) || Sim.IsComplete;
ImGui.BeginDisabled(cannotUse); ImGui.BeginDisabled(cannotUse);
@@ -97,7 +97,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
AppendAction(action); AppendAction(action);
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
ImGui.SetTooltip($"{action.GetName(ClassJob)}\n{baseAction.GetTooltip(Simulator, true)}"); ImGui.SetTooltip($"{action.GetName(ClassJob)}\n{baseAction.GetTooltip(Sim, true)}");
ImGui.EndDisabled(); ImGui.EndDisabled();
@@ -210,11 +210,11 @@ public sealed partial class SimulatorWindow : Window, IDisposable
ImGui.SameLine(0, 0); ImGui.SameLine(0, 0);
foreach (var effect in Enum.GetValues<EffectType>()) foreach (var effect in Enum.GetValues<EffectType>())
{ {
var duration = Simulator.GetEffectDuration(effect); var duration = Sim.GetEffectDuration(effect);
if (duration == 0) if (duration == 0)
continue; continue;
var strength = Simulator.GetEffectStrength(effect); var strength = Sim.GetEffectStrength(effect);
var icon = effect.GetIcon(strength); var icon = effect.GetIcon(strength);
var iconSize = GetEffectSize(icon); var iconSize = GetEffectSize(icon);
@@ -6,7 +6,7 @@ using System.Numerics;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public sealed partial class SimulatorWindow : Window, IDisposable public sealed partial class Simulator : Window, IDisposable
{ {
private readonly record struct SynthDrawParams private readonly record struct SynthDrawParams
{ {
@@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace Craftimizer.Plugin.Windows; namespace Craftimizer.Plugin.Windows;
public sealed partial class SimulatorWindow : Window, IDisposable public sealed partial class Simulator : Window, IDisposable
{ {
private Task SolverTask { get; set; } = Task.CompletedTask; private Task SolverTask { get; set; } = Task.CompletedTask;
private CancellationTokenSource SolverTaskToken { get; set; } = new(); private CancellationTokenSource SolverTaskToken { get; set; } = new();
@@ -27,7 +27,7 @@ public sealed partial class SimulatorWindow : Window, IDisposable
private SimulationState? GenerateSolverState() private SimulationState? GenerateSolverState()
{ {
if (Simulator is SimulatorNoRandom) if (Sim is SimulatorNoRandom)
{ {
if (!Actions.Exists(a => a.Response != ActionResponse.UsedAction)) if (!Actions.Exists(a => a.Response != ActionResponse.UsedAction))
return LatestState; return LatestState;