diff --git a/Craftimizer/Configuration.cs b/Craftimizer/Configuration.cs index 3ff635f..24bb980 100644 --- a/Craftimizer/Configuration.cs +++ b/Craftimizer/Configuration.cs @@ -223,7 +223,13 @@ public partial class Configuration [JsonSourceGenerationOptions(Converters = [typeof(StoredActionTypeConverter)])] [JsonSerializable(typeof(Configuration))] - internal sealed partial class JsonContext : JsonSerializerContext { } + internal sealed partial class JsonContext : JsonSerializerContext + { + public static JsonSerializerOptions DeserializeOptions { get; } = new() + { + Converters = { new StoredActionTypeConverter() } + }; + } public void Save() { @@ -240,7 +246,7 @@ public partial class Configuration using var stream = f.OpenRead(); // System.InvalidOperationException: Setting init-only properties is not supported in source generation mode. - return JsonSerializer.Deserialize(stream, JsonContext.Default.Options) ?? new(); + return JsonSerializer.Deserialize(stream, JsonContext.DeserializeOptions) ?? new(); } return new(); } diff --git a/Craftimizer/Craftimizer.csproj b/Craftimizer/Craftimizer.csproj index 64d111d..985cdec 100644 --- a/Craftimizer/Craftimizer.csproj +++ b/Craftimizer/Craftimizer.csproj @@ -38,10 +38,11 @@ - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Craftimizer/LuminaSheets.cs b/Craftimizer/LuminaSheets.cs index 5a0ea45..acff266 100644 --- a/Craftimizer/LuminaSheets.cs +++ b/Craftimizer/LuminaSheets.cs @@ -1,4 +1,4 @@ -using Dalamud; +using Dalamud.Game; using ExdSheets; using Lumina.Excel; using System.Collections.Concurrent; diff --git a/Craftimizer/Plugin.cs b/Craftimizer/Plugin.cs index f8281d5..1556960 100644 --- a/Craftimizer/Plugin.cs +++ b/Craftimizer/Plugin.cs @@ -5,7 +5,8 @@ using Craftimizer.Simulator.Actions; using Craftimizer.Utils; using Craftimizer.Windows; using Dalamud.Interface.ImGuiNotification; -using Dalamud.Interface.Internal; +using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Windowing; using Dalamud.Plugin; using System; @@ -19,7 +20,7 @@ public sealed class Plugin : IDalamudPlugin public string Version { get; } public string Author { get; } public string BuildConfiguration { get; } - public IDalamudTextureWrap Icon { get; } + public ISharedImmediateTexture Icon { get; } public WindowSystem WindowSystem { get; } public Settings SettingsWindow { get; } @@ -32,11 +33,10 @@ public sealed class Plugin : IDalamudPlugin public Configuration Configuration { get; } public Hooks Hooks { get; } public Chat Chat { get; } - public IconManager IconManager { get; } public CommunityMacros CommunityMacros { get; } public AttributeCommandManager AttributeCommandManager { get; } - public Plugin(DalamudPluginInterface pluginInterface) + public Plugin(IDalamudPluginInterface pluginInterface) { Service.Initialize(this, pluginInterface); @@ -44,7 +44,6 @@ public sealed class Plugin : IDalamudPlugin Configuration = Configuration.Load(); Hooks = new(); Chat = new(); - IconManager = new(); CommunityMacros = new(); AttributeCommandManager = new(); @@ -156,10 +155,8 @@ public sealed class Plugin : IDalamudPlugin public IActiveNotification DisplayNotification(Notification notification) { - notification.InitialDuration = TimeSpan.FromSeconds(5); var ret = Service.NotificationManager.AddNotification(notification); - if (notification.Icon != null) - ret.SetIconTexture(Icon); + // ret.SetIconTexture(Icon.RentAsync().ContinueWith(t => (IDalamudTextureWrap?)t)); return ret; } @@ -173,6 +170,5 @@ public sealed class Plugin : IDalamudPlugin EditorWindow?.Dispose(); ClipboardWindow?.Dispose(); Hooks.Dispose(); - IconManager.Dispose(); } } diff --git a/Craftimizer/Service.cs b/Craftimizer/Service.cs index 38130e1..5a12113 100644 --- a/Craftimizer/Service.cs +++ b/Craftimizer/Service.cs @@ -11,7 +11,7 @@ namespace Craftimizer.Plugin; public sealed class Service { #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - [PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } + [PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } [PluginService] public static ICommandManager CommandManager { get; private set; } [PluginService] public static IObjectTable Objects { get; private set; } [PluginService] public static ISigScanner SigScanner { get; private set; } @@ -30,11 +30,10 @@ public sealed class Service public static Configuration Configuration => Plugin.Configuration; public static WindowSystem WindowSystem => Plugin.WindowSystem; public static Chat Chat => Plugin.Chat; - public static IconManager IconManager => Plugin.IconManager; public static CommunityMacros CommunityMacros => Plugin.CommunityMacros; #pragma warning restore CS8618 - internal static void Initialize(Plugin plugin, DalamudPluginInterface iface) + internal static void Initialize(Plugin plugin, IDalamudPluginInterface iface) { Plugin = plugin; iface.Create(); diff --git a/Craftimizer/SimulatorUtils.cs b/Craftimizer/SimulatorUtils.cs index 7208bbf..8369925 100644 --- a/Craftimizer/SimulatorUtils.cs +++ b/Craftimizer/SimulatorUtils.cs @@ -1,7 +1,6 @@ using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using Dalamud.Game.Text.SeStringHandling.Payloads; -using Dalamud.Interface.Internal; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Game.UI; using ExdSheets; @@ -15,6 +14,8 @@ using ActionType = Craftimizer.Simulator.Actions.ActionType; using ClassJob = Craftimizer.Simulator.ClassJob; using Condition = Craftimizer.Simulator.Condition; using Status = ExdSheets.Status; +using Dalamud.Interface.Textures; +using Craftimizer.Utils; namespace Craftimizer.Plugin; @@ -86,15 +87,15 @@ internal static class ActionUtils return "Unknown"; } - public static IDalamudTextureWrap GetIcon(this ActionType me, ClassJob classJob) + public static ISharedImmediateTexture GetIcon(this ActionType me, ClassJob classJob) { var (craftAction, action) = GetActionRow(me, classJob); if (craftAction != null) - return Service.IconManager.GetIcon(craftAction.Icon); + return IconManager.GetIcon(craftAction.Icon); if (action != null) - return Service.IconManager.GetIcon(action.Icon); + return IconManager.GetIcon(action.Icon); // Old "Steady Hand" action icon - return Service.IconManager.GetIcon(1953); + return IconManager.GetIcon(1953); } public static ActionType? GetActionTypeFromId(uint actionId, ClassJob classJob, bool isCraftAction) @@ -151,7 +152,7 @@ internal static class ClassJobUtils LuminaSheets.ClassJobSheet.GetRow(me.GetClassJobIndex())!.ExpArrayIndex; public static unsafe short GetPlayerLevel(this ClassJob me) => - PlayerState.Instance()->ClassJobLevelArray[me.GetExpArrayIdx()]; + PlayerState.Instance()->ClassJobLevels[me.GetExpArrayIdx()]; public static unsafe bool CanPlayerUseManipulation(this ClassJob me) => UIState.Instance()->IsUnlockLinkUnlockedOrQuestCompleted(ActionType.Manipulation.GetActionRow(me).Action!.UnlockLink.Row); @@ -330,8 +331,8 @@ internal static class EffectUtils return (ushort)iconId; } - public static IDalamudTextureWrap GetIcon(this EffectType me, int strength) => - Service.IconManager.GetIcon(me.GetIconId(strength)); + public static ISharedImmediateTexture GetIcon(this EffectType me, int strength) => + IconManager.GetIcon(me.GetIconId(strength)); public static string GetTooltip(this EffectType me, int strength, int duration) { diff --git a/Craftimizer/Utils/AttributeCommandManager.cs b/Craftimizer/Utils/AttributeCommandManager.cs index ef17895..2316f92 100644 --- a/Craftimizer/Utils/AttributeCommandManager.cs +++ b/Craftimizer/Utils/AttributeCommandManager.cs @@ -29,9 +29,9 @@ public sealed class AttributeCommandManager : IDisposable var takesParams = method.GetParameters().Length != 0; - CommandInfo.HandlerDelegate handler; + IReadOnlyCommandInfo.HandlerDelegate handler; if (takesParams) - handler = method.CreateDelegate(target); + handler = method.CreateDelegate(target); else { var invoker = method.CreateDelegate(target); diff --git a/Craftimizer/Utils/Chat.cs b/Craftimizer/Utils/Chat.cs index 45732a9..f276073 100644 --- a/Craftimizer/Utils/Chat.cs +++ b/Craftimizer/Utils/Chat.cs @@ -1,6 +1,5 @@ using Craftimizer.Plugin; using Dalamud.Utility.Signatures; -using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; using System; @@ -10,15 +9,11 @@ namespace Craftimizer.Utils; // https://github.com/Caraxi/SimpleTweaksPlugin/blob/0973b93931cdf8a1b01153984d62f76d998747ff/Utility/ChatHelper.cs#L17 public sealed unsafe class Chat { - private delegate void SendChatDelegate(UIModule* uiModule, Utf8String* message, Utf8String* historyMessage, bool pushToHistory); - private delegate void SanitizeStringDelegate(Utf8String* data, int flags, Utf8String* buffer); + private delegate void SendChatDelegate(UIModule* @this, Utf8String* message, Utf8String* historyMessage, bool pushToHistory); [Signature("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9")] private readonly SendChatDelegate sendChat = null!; - [Signature("E8 ?? ?? ?? ?? EB 0A 48 8D 4C 24 ?? E8 ?? ?? ?? ?? 48 8D 8D")] - private readonly SanitizeStringDelegate sanitizeString = null!; - public Chat() { Service.GameInteropProvider.InitializeFromAttributes(this); @@ -26,12 +21,11 @@ public sealed unsafe class Chat public void SendMessage(string message) { - if (string.IsNullOrWhiteSpace(message)) - throw new ArgumentException("Message is empty", nameof(message)); + ArgumentException.ThrowIfNullOrWhiteSpace(message); var str = Utf8String.FromString(message); - sanitizeString(str, 0x27F, null); - sendChat(Framework.Instance()->GetUiModule(), str, null, false); + str->SanitizeString(0x27F, null); + sendChat(UIModule.Instance(), str, null, false); str->Dtor(true); } } diff --git a/Craftimizer/Utils/Gearsets.cs b/Craftimizer/Utils/Gearsets.cs index d0a8377..2f5bc10 100644 --- a/Craftimizer/Utils/Gearsets.cs +++ b/Craftimizer/Utils/Gearsets.cs @@ -12,13 +12,13 @@ public static unsafe class Gearsets { public record struct GearsetStats(int CP, int Craftsmanship, int Control); public record struct GearsetMateria(ushort Type, ushort Grade); - public record struct GearsetItem(uint itemId, bool isHq, GearsetMateria[] materia); + public record struct GearsetItem(uint ItemId, bool IsHq, GearsetMateria[] Materia); private static readonly GearsetStats BaseStats = new(180, 0, 0); - public const uint ParamCP = 11; - public const uint ParamCraftsmanship = 70; - public const uint ParamControl = 71; + public const int ParamCP = 11; + public const int ParamCraftsmanship = 70; + public const int ParamControl = 71; private static readonly int[] LevelToCLvlLUT; @@ -44,26 +44,26 @@ public static unsafe class Gearsets for (var i = 0; i < container->Size; ++i) { var item = container->Items[i]; - items[i] = new(item.ItemID, item.Flags.HasFlag(InventoryItem.ItemFlags.HQ), GetMaterias(item.Materia, item.MateriaGrade)); + items[i] = new(item.ItemId, item.Flags.HasFlag(InventoryItem.ItemFlags.HighQuality), GetMaterias(item.Materia, item.MateriaGrades)); } return items; } public static GearsetItem[] GetGearsetItems(RaptureGearsetModule.GearsetEntry* entry) { - var gearsetItems = entry->ItemsSpan; + var gearsetItems = entry->Items; var items = new GearsetItem[14]; for (var i = 0; i < 14; ++i) { var item = gearsetItems[i]; - items[i] = new(item.ItemID % 1000000, item.ItemID > 1000000, GetMaterias(item.Materia, item.MateriaGrade)); + items[i] = new(item.ItemId % 1000000, item.ItemId > 1000000, GetMaterias(item.Materia, item.MateriaGrades)); } return items; } public static GearsetStats CalculateGearsetItemStats(GearsetItem gearsetItem) { - var item = LuminaSheets.ItemSheet.GetRow(gearsetItem.itemId)!; + var item = LuminaSheets.ItemSheet.GetRow(gearsetItem.ItemId)!; int cp = 0, craftsmanship = 0, control = 0; @@ -79,11 +79,11 @@ public static unsafe class Gearsets foreach (var statIncrease in item.BaseParam.Zip(item.BaseParamValue)) IncreaseStat(statIncrease.First.Row, statIncrease.Second); - if (gearsetItem.isHq) + if (gearsetItem.IsHq) foreach (var statIncrease in item.BaseParamSpecial.Zip(item.BaseParamValueSpecial)) IncreaseStat(statIncrease.First.Row, statIncrease.Second); - foreach (var gearsetMateria in gearsetItem.materia) + foreach (var gearsetMateria in gearsetItem.Materia) { if (gearsetMateria.Type == 0) continue; @@ -131,23 +131,23 @@ public static unsafe class Gearsets }; public static bool IsItem(GearsetItem item, uint itemId) => - item.itemId == itemId; + item.ItemId == itemId; public static bool IsSpecialistSoulCrystal(GearsetItem item) { - if (item.itemId == 0) + if (item.ItemId == 0) return false; - var luminaItem = LuminaSheets.ItemSheet.GetRow(item.itemId)!; + var luminaItem = LuminaSheets.ItemSheet.GetRow(item.ItemId)!; // Soul Crystal ItemUICategory DoH Category return luminaItem.ItemUICategory.Row == 62 && luminaItem.ClassJobUse.Value!.ClassJobCategory.Row == 33; } public static bool IsSplendorousTool(GearsetItem item) => - LuminaSheets.ItemSheetEnglish.GetRow(item.itemId)!.Description.ToDalamudString().TextValue.Contains("Increases to quality are 1.75 times higher than normal when material condition is Good.", StringComparison.Ordinal); + LuminaSheets.ItemSheetEnglish.GetRow(item.ItemId)!.Description.ToDalamudString().TextValue.Contains("Increases to quality are 1.75 times higher than normal when material condition is Good.", StringComparison.Ordinal); public static int CalculateCLvl(int level) => - (level > 0 && level <= 90) ? + (level > 0 && level <= 100) ? LevelToCLvlLUT[level - 1] : throw new ArgumentOutOfRangeException(nameof(level), level, "Level is out of range."); @@ -197,7 +197,7 @@ public static unsafe class Gearsets return cap == 0 ? int.MaxValue : cap; } - private static GearsetMateria[] GetMaterias(ushort* types, byte* grades) + private static GearsetMateria[] GetMaterias(ReadOnlySpan types, ReadOnlySpan grades) { var materia = new GearsetMateria[5]; for (var i = 0; i < 5; ++i) diff --git a/Craftimizer/Utils/IconManager.cs b/Craftimizer/Utils/IconManager.cs index cf1d2a7..329544b 100644 --- a/Craftimizer/Utils/IconManager.cs +++ b/Craftimizer/Utils/IconManager.cs @@ -1,81 +1,27 @@ using Craftimizer.Plugin; -using Dalamud.Interface.Internal; -using Dalamud.Plugin.Services; +using Dalamud.Interface.Textures; using System; -using System.Collections.Generic; -using System.IO; using System.Reflection; namespace Craftimizer.Utils; -public sealed class IconManager : IDisposable +public static class IconManager { - private readonly Dictionary iconCache = []; - private readonly Dictionary hqIconCache = []; - private readonly Dictionary textureCache = []; - private readonly Dictionary assemblyCache = []; - - public IDalamudTextureWrap GetIcon(uint id) + public static ISharedImmediateTexture GetIcon(uint id, bool isHq = false) { - if (!iconCache.TryGetValue(id, out var ret)) - iconCache.Add(id, ret = Service.TextureProvider.GetIcon(id) ?? - throw new ArgumentException($"Invalid icon id {id}", nameof(id))); - return ret; + return Service.TextureProvider.GetFromGameIcon(new GameIconLookup(id, itemHq: isHq)); } - public IDalamudTextureWrap GetHqIcon(uint id, bool isHq = true) + public static ISharedImmediateTexture GetTexture(string path) { - if (!isHq) - return GetIcon(id); - if (!hqIconCache.TryGetValue(id, out var ret)) - hqIconCache.Add(id, ret = Service.TextureProvider.GetIcon(id, ITextureProvider.IconFlags.HiRes | ITextureProvider.IconFlags.ItemHighQuality) ?? - throw new ArgumentException($"Invalid hq icon id {id}", nameof(id))); - return ret; + return Service.TextureProvider.GetFromGame(path); } - public IDalamudTextureWrap GetTexture(string path) + public static ISharedImmediateTexture GetAssemblyTexture(string filename) { - if (!textureCache.TryGetValue(path, out var ret)) - textureCache.Add(path, ret = Service.TextureProvider.GetTextureFromGame(path) ?? - throw new ArgumentException($"Invalid texture {path}", nameof(path))); - return ret; + return Service.TextureProvider.GetFromManifestResource(Assembly.GetExecutingAssembly(), $"Craftimizer.{filename}"); } - public IDalamudTextureWrap GetAssemblyTexture(string filename) - { - if (!assemblyCache.TryGetValue(filename, out var ret)) - assemblyCache.Add(filename, ret = GetAssemblyTextureInternal(filename)); - return ret; - } - - private static IDalamudTextureWrap GetAssemblyTextureInternal(string filename) - { - var assembly = Assembly.GetExecutingAssembly(); - byte[] iconData; - using (var stream = assembly.GetManifestResourceStream($"Craftimizer.{filename}") ?? throw new InvalidDataException($"Could not load resource {filename}")) - { - iconData = new byte[stream.Length]; - _ = stream.Read(iconData); - } - return Service.PluginInterface.UiBuilder.LoadImage(iconData); - } - - public void Dispose() - { - foreach (var image in iconCache.Values) - image.Dispose(); - iconCache.Clear(); - - foreach (var image in hqIconCache.Values) - image.Dispose(); - hqIconCache.Clear(); - - foreach (var image in textureCache.Values) - image.Dispose(); - textureCache.Clear(); - - foreach (var image in assemblyCache.Values) - image.Dispose(); - assemblyCache.Clear(); - } + public static nint GetHandle(this ISharedImmediateTexture me) => + me.GetWrapOrEmpty().ImGuiHandle; } diff --git a/Craftimizer/Utils/MacroCopy.cs b/Craftimizer/Utils/MacroCopy.cs index 225e8a0..8cce6be 100644 --- a/Craftimizer/Utils/MacroCopy.cs +++ b/Craftimizer/Utils/MacroCopy.cs @@ -1,7 +1,7 @@ using Craftimizer.Plugin; using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; -using Dalamud.Interface.Internal.Notifications; +using Dalamud.Interface.ImGuiNotification; using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Misc; diff --git a/Craftimizer/Windows/MacroClipboard.cs b/Craftimizer/Windows/MacroClipboard.cs index 0d44d81..1b4d433 100644 --- a/Craftimizer/Windows/MacroClipboard.cs +++ b/Craftimizer/Windows/MacroClipboard.cs @@ -1,6 +1,5 @@ using Craftimizer.Plugin; using Dalamud.Interface; -using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using ImGuiNET; @@ -8,6 +7,7 @@ using System; using System.Collections.Generic; using System.Numerics; using System.Linq; +using Dalamud.Interface.ImGuiNotification; namespace Craftimizer.Windows; diff --git a/Craftimizer/Windows/MacroEditor.cs b/Craftimizer/Windows/MacroEditor.cs index 158e408..ba694e1 100644 --- a/Craftimizer/Windows/MacroEditor.cs +++ b/Craftimizer/Windows/MacroEditor.cs @@ -8,9 +8,11 @@ using Dalamud.Game.Text; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.GameFonts; +using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.Internal; -using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface.ManagedFontAtlas; +using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using Dalamud.Utility; @@ -42,7 +44,7 @@ public sealed class MacroEditor : Window, IDisposable Craftsmanship = Math.Clamp(value.Craftsmanship, 0, 9000), Control = Math.Clamp(value.Control, 0, 9000), CP = Math.Clamp(value.CP, 180, 1000), - Level = Math.Clamp(value.Level, 1, 90), + Level = Math.Clamp(value.Level, 1, 100), CLvl = Gearsets.CalculateCLvl(value.Level), }; } @@ -91,16 +93,16 @@ public sealed class MacroEditor : Window, IDisposable private Solver.Solver? SolverObject { get; set; } private bool SolverRunning => SolverTokenSource != null; - private IDalamudTextureWrap ExpertBadge { get; } - private IDalamudTextureWrap CollectibleBadge { get; } - private IDalamudTextureWrap SplendorousBadge { get; } - private IDalamudTextureWrap SpecialistBadge { get; } - private IDalamudTextureWrap NoManipulationBadge { get; } - private IDalamudTextureWrap ManipulationBadge { get; } - private IDalamudTextureWrap WellFedBadge { get; } - private IDalamudTextureWrap MedicatedBadge { get; } - private IDalamudTextureWrap InControlBadge { get; } - private IDalamudTextureWrap EatFromTheHandBadge { get; } + private ISharedImmediateTexture ExpertBadge { get; } + private ISharedImmediateTexture CollectibleBadge { get; } + private ISharedImmediateTexture SplendorousBadge { get; } + private ISharedImmediateTexture SpecialistBadge { get; } + private ISharedImmediateTexture NoManipulationBadge { get; } + private ISharedImmediateTexture ManipulationBadge { get; } + private ISharedImmediateTexture WellFedBadge { get; } + private ISharedImmediateTexture MedicatedBadge { get; } + private ISharedImmediateTexture InControlBadge { get; } + private ISharedImmediateTexture EatFromTheHandBadge { get; } private IFontHandle AxisFont { get; } private string popupSaveAsMacroName = string.Empty; @@ -125,16 +127,16 @@ public sealed class MacroEditor : Window, IDisposable foreach (var action in DefaultActions) AddStep(action); - ExpertBadge = Service.IconManager.GetAssemblyTexture("Graphics.expert_badge.png"); - CollectibleBadge = Service.IconManager.GetAssemblyTexture("Graphics.collectible_badge.png"); - SplendorousBadge = Service.IconManager.GetAssemblyTexture("Graphics.splendorous.png"); - SpecialistBadge = Service.IconManager.GetAssemblyTexture("Graphics.specialist.png"); - NoManipulationBadge = Service.IconManager.GetAssemblyTexture("Graphics.no_manip.png"); + ExpertBadge = IconManager.GetAssemblyTexture("Graphics.expert_badge.png"); + CollectibleBadge = IconManager.GetAssemblyTexture("Graphics.collectible_badge.png"); + SplendorousBadge = IconManager.GetAssemblyTexture("Graphics.splendorous.png"); + SpecialistBadge = IconManager.GetAssemblyTexture("Graphics.specialist.png"); + NoManipulationBadge = IconManager.GetAssemblyTexture("Graphics.no_manip.png"); ManipulationBadge = ActionType.Manipulation.GetIcon(RecipeData.ClassJob); - WellFedBadge = Service.IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(48)!.Icon); - MedicatedBadge = Service.IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(49)!.Icon); - InControlBadge = Service.IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(356)!.Icon); - EatFromTheHandBadge = Service.IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(357)!.Icon); + WellFedBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(48)!.Icon); + MedicatedBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(49)!.Icon); + InControlBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(356)!.Icon); + EatFromTheHandBadge = IconManager.GetIcon(LuminaSheets.StatusSheet.GetRow(357)!.Icon); AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis14)); IsOpen = true; @@ -223,7 +225,7 @@ public sealed class MacroEditor : Window, IDisposable uv0 /= new Vector2(56); uv1 /= new Vector2(56); - ImGui.Image(Service.IconManager.GetIcon(RecipeData.ClassJob.GetIconId()).ImGuiHandle, new Vector2(imageSize), uv0, uv1); + ImGui.Image(IconManager.GetIcon(RecipeData.ClassJob.GetIconId()).GetHandle(), new Vector2(imageSize), uv0, uv1); ImGui.SameLine(0, 5); AxisFont.Text(textClassName); @@ -274,7 +276,7 @@ public sealed class MacroEditor : Window, IDisposable ImGui.TableSetupColumn("col3", ImGuiTableColumnFlags.WidthStretch, 2); ImGui.TableNextColumn(); - var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(99)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; + var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(100)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; ImGuiUtils.AlignCentered( ImGui.CalcTextSize(SqText.LevelPrefix.ToIconString()).X + 5 + levelTextWidth); @@ -287,14 +289,14 @@ public sealed class MacroEditor : Window, IDisposable bool textChanged; unsafe { - textChanged = ImGui.InputText("##levelText", ref levelText, 8, ImGuiInputTextFlags.CallbackCharFilter | ImGuiInputTextFlags.AutoSelectAll, LevelInputCallback); + textChanged = ImGui.InputText("##levelText", ref levelText, 12, ImGuiInputTextFlags.CallbackCharFilter | ImGuiInputTextFlags.AutoSelectAll, LevelInputCallback); } if (textChanged) CharacterStats = CharacterStats with { Level = SqText.TryParseLevelString(levelText, out var newLevel) - ? Math.Clamp(newLevel, 1, 90) + ? Math.Clamp(newLevel, 1, 100) : 1 }; if (ImGui.IsItemHovered()) @@ -312,7 +314,7 @@ public sealed class MacroEditor : Window, IDisposable { var v = CharacterStats.HasSplendorousBuff; var tint = v ? Vector4.One : disabledTint; - if (ImGui.ImageButton(SplendorousBadge.ImGuiHandle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + if (ImGui.ImageButton(SplendorousBadge.GetHandle(), new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) CharacterStats = CharacterStats with { HasSplendorousBuff = !v }; } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) @@ -330,7 +332,7 @@ public sealed class MacroEditor : Window, IDisposable using (var d = ImRaii.Disabled(specialistLevel > CharacterStats.Level)) { var tint = new Vector4(0.99f, 0.97f, 0.62f, 1f) * (v ? Vector4.One : disabledTint); - if (ImGui.ImageButton(SpecialistBadge.ImGuiHandle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + if (ImGui.ImageButton(SpecialistBadge.GetHandle(), new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) { v = !v; newIsSpecialist = v; @@ -346,7 +348,7 @@ public sealed class MacroEditor : Window, IDisposable { var v = CharacterStats.CanUseManipulation && manipLevel <= CharacterStats.Level; var tint = (v || manipLevel > CharacterStats.Level) ? disabledTint : Vector4.One; - if (ImGui.ImageButton(v ? ManipulationBadge.ImGuiHandle : NoManipulationBadge.ImGuiHandle, new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) + if (ImGui.ImageButton(v ? ManipulationBadge.GetHandle() : NoManipulationBadge.GetHandle(), new Vector2(imageButtonSize), default, Vector2.One, imageButtonPadding, default, tint)) CharacterStats = CharacterStats with { CanUseManipulation = !v }; } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) @@ -356,8 +358,9 @@ public sealed class MacroEditor : Window, IDisposable ImGui.TableNextColumn(); (uint ItemId, bool HQ)? newFoodBuff = null; - var buffImageSize = new Vector2(imageSize * WellFedBadge.Width / WellFedBadge.Height, imageSize); - ImGui.Image(WellFedBadge.ImGuiHandle, buffImageSize); + var buffBadge = WellFedBadge.GetWrapOrEmpty(); + var buffImageSize = new Vector2(imageSize * buffBadge.Width / buffBadge.Height, imageSize); + ImGui.Image(buffBadge.ImGuiHandle, buffImageSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip("Food"); ImGui.SameLine(0, 5); @@ -392,8 +395,9 @@ public sealed class MacroEditor : Window, IDisposable } (uint ItemId, bool HQ)? newMedicineBuff = null; - buffImageSize = new Vector2(imageSize * MedicatedBadge.Width / MedicatedBadge.Height, imageSize); - ImGui.Image(MedicatedBadge.ImGuiHandle, buffImageSize); + buffBadge = MedicatedBadge.GetWrapOrEmpty(); + buffImageSize = new Vector2(imageSize * buffBadge.Width / buffBadge.Height, imageSize); + ImGui.Image(buffBadge.ImGuiHandle, buffImageSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip("Medicine"); ImGui.SameLine(0, 5); @@ -430,8 +434,9 @@ public sealed class MacroEditor : Window, IDisposable ImGui.TableNextColumn(); int? newFCCraftsmanshipBuff = null; - buffImageSize = new Vector2(imageSize * MedicatedBadge.Width / MedicatedBadge.Height, imageSize); - ImGui.Image(EatFromTheHandBadge.ImGuiHandle, buffImageSize); + buffBadge = EatFromTheHandBadge.GetWrapOrEmpty(); + buffImageSize = new Vector2(imageSize * buffBadge.Width / buffBadge.Height, imageSize); + ImGui.Image(buffBadge.ImGuiHandle, buffImageSize); var fcBuffName = "Eat from the Hand"; var fcStatName = "Craftsmanship"; if (ImGui.IsItemHovered()) @@ -458,8 +463,9 @@ public sealed class MacroEditor : Window, IDisposable } int? newFCControlBuff = null; - buffImageSize = new Vector2(imageSize * MedicatedBadge.Width / MedicatedBadge.Height, imageSize); - ImGui.Image(InControlBadge.ImGuiHandle, buffImageSize); + buffBadge = InControlBadge.GetWrapOrEmpty(); + buffImageSize = new Vector2(imageSize * buffBadge.Width / buffBadge.Height, imageSize); + ImGui.Image(buffBadge.ImGuiHandle, buffImageSize); fcBuffName = "In Control"; fcStatName = "Control"; if (ImGui.IsItemHovered()) @@ -709,7 +715,8 @@ public sealed class MacroEditor : Window, IDisposable var isCollectable = RecipeData.Recipe.ItemResult.Value!.IsCollectable; var imageSize = ImGui.GetFrameHeight(); var textSize = ImGui.GetFontSize(); - var badgeSize = new Vector2(textSize * ExpertBadge.Width / ExpertBadge.Height, textSize); + var badge = ExpertBadge.GetWrapOrEmpty(); + var badgeSize = new Vector2(textSize * badge.Width / badge.Height, textSize); var badgeOffset = (imageSize - badgeSize.Y) / 2; var rightSideWidth = @@ -719,7 +726,7 @@ public sealed class MacroEditor : Window, IDisposable (isExpert ? badgeSize.X + 3 : 0); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIcon(RecipeData.Recipe.ItemResult.Value!.Icon).ImGuiHandle, new Vector2(imageSize)); + ImGui.Image(IconManager.GetIcon(RecipeData.Recipe.ItemResult.Value!.Icon).GetHandle(), new Vector2(imageSize)); ImGui.SameLine(0, 5); @@ -757,7 +764,7 @@ public sealed class MacroEditor : Window, IDisposable uv1 /= new Vector2(56); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().FramePadding.Y / 2); - ImGui.Image(Service.IconManager.GetIcon(classJob.GetIconId()).ImGuiHandle, new Vector2(imageSize), uv0, uv1); + ImGui.Image(IconManager.GetIcon(classJob.GetIconId()).GetHandle(), new Vector2(imageSize), uv0, uv1); ImGui.SameLine(0, 5); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (fontHandle.FontSize - textLevelSize.Y) / 2); ImGui.TextUnformatted(textLevel); @@ -785,7 +792,7 @@ public sealed class MacroEditor : Window, IDisposable { ImGui.SameLine(0, 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + badgeOffset); - ImGui.Image(CollectibleBadge.ImGuiHandle, badgeSize); + ImGui.Image(CollectibleBadge.GetHandle(), badgeSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Collectible"); } @@ -794,7 +801,7 @@ public sealed class MacroEditor : Window, IDisposable { ImGui.SameLine(0, 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + badgeOffset); - ImGui.Image(ExpertBadge.ImGuiHandle, badgeSize); + ImGui.Image(ExpertBadge.GetHandle(), badgeSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Expert Recipe"); } @@ -881,11 +888,11 @@ public sealed class MacroEditor : Window, IDisposable var hqCount = HQIngredientCounts[idx]; var canHq = ingredient.Item.CanBeHq; - var icon = Service.IconManager.GetHqIcon(ingredient.Item.Icon, canHq); + var icon = IconManager.GetIcon(ingredient.Item.Icon, canHq); var imageSize = ImGui.GetFrameHeight(); using (var d = ImRaii.Disabled(!canHq)) - ImGui.Image(icon.ImGuiHandle, new Vector2(imageSize)); + ImGui.Image(icon.GetHandle(), new Vector2(imageSize)); if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { if (canHq) @@ -953,12 +960,12 @@ public sealed class MacroEditor : Window, IDisposable { var actionBase = actions[i].Base(); 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) && !SolverRunning) + if (ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(imageSize), default, Vector2.One, 0, default, !canUse ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One) && !SolverRunning) AddStep(actions[i]); if (!canUse && (CharacterStats.Level < actionBase.Level || (actions[i] == ActionType.Manipulation && !CharacterStats.CanUseManipulation) || - (actions[i] is ActionType.HeartAndSoul or ActionType.CarefulObservation && !CharacterStats.IsSpecialist) + (actions[i] is ActionType.HeartAndSoul or ActionType.CarefulObservation or ActionType.QuickInnovation && !CharacterStats.IsSpecialist) ) ) { @@ -977,7 +984,7 @@ public sealed class MacroEditor : Window, IDisposable if (_source) { ImGuiExtras.SetDragDropPayload("macroActionInsert", actions[i]); - ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize)); + ImGui.ImageButton(actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(imageSize)); } } } @@ -1091,7 +1098,7 @@ public sealed class MacroEditor : Window, IDisposable using (var group = ImRaii.Group()) { - var icon = effect.GetIcon(effects.GetStrength(effect)); + var icon = effect.GetIcon(effects.GetStrength(effect)).GetWrapOrEmpty(); var size = new Vector2(iconHeight * icon.Width / icon.Height, iconHeight); ImGui.Image(icon.ImGuiHandle, size); @@ -1140,7 +1147,7 @@ public sealed class MacroEditor : Window, IDisposable var actionBase = action.Base(); var failedAction = response != ActionResponse.UsedAction; using var id = ImRaii.PushId(i); - if (ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One)) + if (ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).GetHandle(), new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One)) RemoveStep(i); if (response is ActionResponse.ActionNotUnlocked || ( @@ -1169,7 +1176,7 @@ public sealed class MacroEditor : Window, IDisposable if (_source) { ImGuiExtras.SetDragDropPayload("macroAction", i); - ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize)); + ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).GetHandle(), new(imageSize)); } } using (var _target = ImRaii.DragDropTarget()) diff --git a/Craftimizer/Windows/MacroList.cs b/Craftimizer/Windows/MacroList.cs index 225c9cd..744fdd2 100644 --- a/Craftimizer/Windows/MacroList.cs +++ b/Craftimizer/Windows/MacroList.cs @@ -274,7 +274,7 @@ public sealed class MacroList : Window, IDisposable var shouldShowMore = i + 1 == itemsPerRow * 2 && i + 1 < itemCount; if (!shouldShowMore) { - ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(miniRowHeight)); + ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(miniRowHeight)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip(macro.Actions[i].GetName(RecipeData!.ClassJob)); } @@ -282,7 +282,7 @@ public sealed class MacroList : Window, IDisposable { var amtMore = itemCount - itemsPerRow * 2; var pos = ImGui.GetCursorPos(); - ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); + ImGui.Image(macro.Actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"{macro.Actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more"); ImGui.SetCursorPos(pos); diff --git a/Craftimizer/Windows/RecipeNote.cs b/Craftimizer/Windows/RecipeNote.cs index 581f30f..d2b72d2 100644 --- a/Craftimizer/Windows/RecipeNote.cs +++ b/Craftimizer/Windows/RecipeNote.cs @@ -10,8 +10,8 @@ using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; using Dalamud.Interface.GameFonts; -using Dalamud.Interface.Internal; using Dalamud.Interface.ManagedFontAtlas; +using Dalamud.Interface.Textures; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; @@ -20,7 +20,6 @@ using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI.Misc; -using FFXIVClientStructs.FFXIV.Component.GUI; using ImGuiNET; using System; using System.Collections.Generic; @@ -108,20 +107,20 @@ public sealed unsafe class RecipeNote : Window, IDisposable private Solver.Solver? BestMacroSolver { get; set; } public bool HasSavedMacro { get; private set; } - private IDalamudTextureWrap ExpertBadge { get; } - private IDalamudTextureWrap CollectibleBadge { get; } - private IDalamudTextureWrap SplendorousBadge { get; } - private IDalamudTextureWrap SpecialistBadge { get; } - private IDalamudTextureWrap NoManipulationBadge { get; } + private ISharedImmediateTexture ExpertBadge { get; } + private ISharedImmediateTexture CollectibleBadge { get; } + private ISharedImmediateTexture SplendorousBadge { get; } + private ISharedImmediateTexture SpecialistBadge { get; } + private ISharedImmediateTexture NoManipulationBadge { get; } private IFontHandle AxisFont { get; } public RecipeNote() : base(WindowNamePinned) { - ExpertBadge = Service.IconManager.GetAssemblyTexture("Graphics.expert_badge.png"); - CollectibleBadge = Service.IconManager.GetAssemblyTexture("Graphics.collectible_badge.png"); - SplendorousBadge = Service.IconManager.GetAssemblyTexture("Graphics.splendorous.png"); - SpecialistBadge = Service.IconManager.GetAssemblyTexture("Graphics.specialist.png"); - NoManipulationBadge = Service.IconManager.GetAssemblyTexture("Graphics.no_manip.png"); + ExpertBadge = IconManager.GetAssemblyTexture("Graphics.expert_badge.png"); + CollectibleBadge = IconManager.GetAssemblyTexture("Graphics.collectible_badge.png"); + SplendorousBadge = IconManager.GetAssemblyTexture("Graphics.splendorous.png"); + SpecialistBadge = IconManager.GetAssemblyTexture("Graphics.specialist.png"); + NoManipulationBadge = IconManager.GetAssemblyTexture("Graphics.no_manip.png"); AxisFont = Service.PluginInterface.UiBuilder.FontAtlas.NewGameFontHandle(new(GameFontFamilyAndSize.Axis14)); RespectCloseHotkey = false; @@ -230,7 +229,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable return false; // Check if RecipeNote has a visible selected recipe - if (!Addon->Unk258->IsVisible) + if (!Addon->GetNodeById(57)->IsVisible()) return false; } @@ -324,8 +323,8 @@ public sealed unsafe class RecipeNote : Window, IDisposable var pos = new Vector2(unit.X, unit.Y); var size = new Vector2(unit.WindowNode->AtkResNode.Width, unit.WindowNode->AtkResNode.Height) * scale; - var node = (AtkResNode*)Addon->Unk458; // unit.GetNodeById(59); - var nodeParent = Addon->Unk258; // unit.GetNodeById(57); + var node = Addon->GetNodeById(59); + var nodeParent = Addon->GetNodeById(57); var newAlpha = unit.WindowNode->AtkResNode.Alpha_2; StyleAlpha = LastAlpha ?? newAlpha; @@ -482,7 +481,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable uv0 /= new Vector2(56); uv1 /= new Vector2(56); - ImGui.Image(Service.IconManager.GetIcon(RecipeData.ClassJob.GetIconId()).ImGuiHandle, new Vector2(imageSize), uv0, uv1); + ImGui.Image(IconManager.GetIcon(RecipeData.ClassJob.GetIconId()).GetHandle(), new Vector2(imageSize), uv0, uv1); ImGui.SameLine(0, 5); if (level != 0) @@ -498,7 +497,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (hasSplendorous) { ImGui.SameLine(0, 3); - ImGui.Image(SplendorousBadge.ImGuiHandle, new Vector2(imageSize)); + ImGui.Image(SplendorousBadge.GetHandle(), new Vector2(imageSize)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Splendorous Tool"); } @@ -506,7 +505,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (hasSpecialist) { ImGui.SameLine(0, 3); - ImGui.Image(SpecialistBadge.ImGuiHandle, new Vector2(imageSize), Vector2.Zero, Vector2.One, new(0.99f, 0.97f, 0.62f, 1f)); + ImGui.Image(SpecialistBadge.GetHandle(), new Vector2(imageSize), Vector2.Zero, Vector2.One, new(0.99f, 0.97f, 0.62f, 1f)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Specialist"); } @@ -514,7 +513,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable if (shouldHaveManip) { ImGui.SameLine(0, 3); - ImGui.Image(NoManipulationBadge.ImGuiHandle, new Vector2(imageSize)); + ImGui.Image(NoManipulationBadge.GetHandle(), new Vector2(imageSize)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"No Manipulation (Missing Job Quest)"); } @@ -588,7 +587,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable ImGuiUtils.TextCentered($"You are missing the required equipment."); ImGuiUtils.AlignCentered(imageSize + 5 + ImGui.CalcTextSize(itemName).X); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIcon(item.Icon).ImGuiHandle, new(imageSize)); + ImGui.Image(IconManager.GetIcon(item.Icon).GetHandle(), new(imageSize)); ImGui.SameLine(0, 5); ImGui.TextUnformatted(itemName); } @@ -597,7 +596,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var status = RecipeData.Recipe.StatusRequired.Value!; var statusName = status.Name.ToDalamudString().ToString(); - var statusIcon = Service.IconManager.GetIcon(status.Icon); + var statusIcon = IconManager.GetIcon(status.Icon).GetWrapOrEmpty(); var imageSize = new Vector2(ImGui.GetFrameHeight() * statusIcon.Width / statusIcon.Height, ImGui.GetFrameHeight()); ImGuiUtils.TextCentered($"You are missing the required status effect."); @@ -668,7 +667,8 @@ public sealed unsafe class RecipeNote : Window, IDisposable var isCollectable = RecipeData.Recipe.ItemResult.Value!.IsCollectable; var imageSize = ImGui.GetFrameHeight(); var textSize = ImGui.GetFontSize(); - var badgeSize = new Vector2(textSize * ExpertBadge.Width / ExpertBadge.Height, textSize); + var badge = ExpertBadge.GetWrapOrEmpty(); + var badgeSize = new Vector2(textSize * badge.Width / badge.Height, textSize); var badgeOffset = (imageSize - badgeSize.Y) / 2; ImGuiUtils.AlignCentered( @@ -680,7 +680,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable ); ImGui.AlignTextToFramePadding(); - ImGui.Image(Service.IconManager.GetIcon(RecipeData.Recipe.ItemResult.Value!.Icon).ImGuiHandle, new Vector2(imageSize)); + ImGui.Image(IconManager.GetIcon(RecipeData.Recipe.ItemResult.Value!.Icon).GetHandle(), new Vector2(imageSize)); ImGui.SameLine(0, 5); ImGui.TextUnformatted(textLevel); @@ -700,7 +700,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { ImGui.SameLine(0, 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + badgeOffset); - ImGui.Image(CollectibleBadge.ImGuiHandle, badgeSize); + ImGui.Image(CollectibleBadge.GetHandle(), badgeSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Collectible"); } @@ -709,7 +709,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { ImGui.SameLine(0, 3); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + badgeOffset); - ImGui.Image(ExpertBadge.ImGuiHandle, badgeSize); + ImGui.Image(ExpertBadge.GetHandle(), badgeSize); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"Expert Recipe"); } @@ -1010,7 +1010,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable var shouldShowMore = i + 1 == itemsPerRow * 2 && i + 1 < itemCount; if (!shouldShowMore) { - ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(miniRowHeight)); + ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(miniRowHeight)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip(actions[i].GetName(RecipeData!.ClassJob)); } @@ -1018,7 +1018,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable { var amtMore = itemCount - itemsPerRow * 2; var pos = ImGui.GetCursorPos(); - ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); + ImGui.Image(actions[i].GetIcon(RecipeData!.ClassJob).GetHandle(), new(miniRowHeight), default, Vector2.One, new(1, 1, 1, .5f)); if (ImGui.IsItemHovered()) ImGuiUtils.Tooltip($"{actions[i].GetName(RecipeData!.ClassJob)}\nand {amtMore} more"); ImGui.SetCursorPos(pos); @@ -1120,15 +1120,18 @@ public sealed unsafe class RecipeNote : Window, IDisposable private static int? GetGearsetForJob(ClassJob job) { var gearsetModule = RaptureGearsetModule.Instance(); - for (var i = 0; i < 100; i++) + var i = -1; + foreach (ref var gearset in gearsetModule->Entries) { - var gearset = gearsetModule->EntriesSpan[i]; + i++; + if (!gearset.Flags.HasFlag(RaptureGearsetModule.GearsetFlag.Exists)) continue; - if (gearset.ID != i) + if (gearset.Id != i) continue; if (gearset.ClassJob != job.GetClassJobIndex()) continue; + return i; } return null; diff --git a/Craftimizer/Windows/Settings.cs b/Craftimizer/Windows/Settings.cs index bd66f2e..0d1322d 100644 --- a/Craftimizer/Windows/Settings.cs +++ b/Craftimizer/Windows/Settings.cs @@ -1,6 +1,7 @@ using Craftimizer.Simulator; using Craftimizer.Simulator.Actions; using Craftimizer.Solver; +using Craftimizer.Utils; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.ManagedFontAtlas; @@ -694,7 +695,7 @@ public sealed class Settings : Window, IDisposable iconTint = new(1, 1f, .5f, 1); else if (isRisky) iconTint = new(1, .5f, .5f, 1); - if (ImGui.ImageButton(actions[i].GetIcon(recipeData.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, iconTint)) + if (ImGui.ImageButton(actions[i].GetIcon(recipeData.ClassJob).GetHandle(), new(imageSize), default, Vector2.One, 0, default, iconTint)) { isDirty = true; if (isEnabled) @@ -932,7 +933,7 @@ public sealed class Settings : Window, IDisposable ImGuiHelpers.ScaledDummy(5); var plugin = Service.Plugin; - var icon = plugin.Icon; + var icon = plugin.Icon.GetWrapOrEmpty(); using (var table = ImRaii.Table("settingsAboutTable", 2)) { diff --git a/Craftimizer/Windows/SynthHelper.cs b/Craftimizer/Windows/SynthHelper.cs index a0236bd..a30ec79 100644 --- a/Craftimizer/Windows/SynthHelper.cs +++ b/Craftimizer/Windows/SynthHelper.cs @@ -310,7 +310,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable isPressed = ImGuiExtras.ButtonBehavior(bb, id, out isHovered, out isHeld, ImGuiButtonFlags.None); } - ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One); + ImGui.ImageButton(action.GetIcon(RecipeData!.ClassJob).GetHandle(), new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One); if (isPressed || IsSuggestedActionExecutionQueued) { if (canExecute && i == 0) @@ -359,7 +359,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable using (var group = ImRaii.Group()) { - var icon = effect.GetIcon(effects.GetStrength(effect)); + var icon = effect.GetIcon(effects.GetStrength(effect)).GetWrapOrEmpty(); var size = new Vector2(iconHeight * icon.Width / icon.Height, iconHeight); ImGui.Image(icon.ImGuiHandle, size); @@ -535,15 +535,15 @@ public sealed unsafe class SynthHelper : Window, IDisposable byte GetEffectStack(ushort id) { - foreach (var status in statusManager->StatusSpan) - if (status.StatusID == id) + foreach (var status in statusManager->Status) + if (status.StatusId == id) return status.StackCount; return 0; } bool HasEffect(ushort id) { - foreach (var status in statusManager->StatusSpan) - if (status.StatusID == id) + foreach (var status in statusManager->Status) + if (status.StatusId == id) return true; return false; } @@ -568,8 +568,8 @@ public sealed unsafe class SynthHelper : Window, IDisposable WasteNot2 = GetEffectStack((ushort)EffectType.WasteNot2.StatusId()), MuscleMemory = GetEffectStack((ushort)EffectType.MuscleMemory.StatusId()), Manipulation = GetEffectStack((ushort)EffectType.Manipulation.StatusId()), - Expedience = HasEffect((ushort)EffectType.Expedience.StatusId()), - TrainedPerfection = HasEffect((ushort)EffectType.TrainedPerfection.StatusId()), + Expedience = GetEffectStack((ushort)EffectType.Expedience.StatusId()), + TrainedPerfection = GetEffectStack((ushort)EffectType.TrainedPerfection.StatusId()), HeartAndSoul = HasEffect((ushort)EffectType.HeartAndSoul.StatusId()), }, ActionStates = CurrentActionStates diff --git a/Craftimizer/packages.lock.json b/Craftimizer/packages.lock.json index 397a713..ba7417f 100644 --- a/Craftimizer/packages.lock.json +++ b/Craftimizer/packages.lock.json @@ -4,19 +4,25 @@ "net8.0-windows7.0": { "DalamudPackager": { "type": "Direct", - "requested": "[2.1.12, )", - "resolved": "2.1.12", - "contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg==" + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" }, "ExdSheets": { "type": "Direct", - "requested": "[1.0.0, )", - "resolved": "1.0.0", - "contentHash": "Zf1btj6qUkrzEm+MVCd2vRWguXizb+Ucy49xWHhFJ5HQj6gtLOxAX2gJqebAtg/uDBbEb9BHx/5Kz7Kuha5+cw==", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "Je/kV/jpZoIEmJVi1ICRnl1/ENB+nyFHX1KZUu3rkxMO8H9uJJ6CA1MdRiOD6OE6If1eGXAL1bLwEupC2Ikraw==", "dependencies": { "Lumina": "3.15.2" } }, + "Lumina": { + "type": "Direct", + "requested": "[3.15.2, )", + "resolved": "3.15.2", + "contentHash": "EnoxYEYMepcvAoXdZhaFJiv2aiDBIPjgkgzxR/+ArOxlrALzCgheTsb5yD39a9sxNIi2tNECT93ulZvYjx8fZg==" + }, "MathNet.Numerics": { "type": "Direct", "requested": "[5.0.0, )", @@ -25,14 +31,9 @@ }, "Meziantou.Analyzer": { "type": "Direct", - "requested": "[2.0.157, )", - "resolved": "2.0.157", - "contentHash": "gQ9xAHvpYeqwOqcyRs5f8kFrTt7Kg2atzjsETGhRjuyGXqKYrN84n52Je6NcGEkZWRwhrQTBJl1wlcsh2se7Fw==" - }, - "Lumina": { - "type": "Transitive", - "resolved": "3.15.2", - "contentHash": "EnoxYEYMepcvAoXdZhaFJiv2aiDBIPjgkgzxR/+ArOxlrALzCgheTsb5yD39a9sxNIi2tNECT93ulZvYjx8fZg==" + "requested": "[2.0.159, )", + "resolved": "2.0.159", + "contentHash": "+Lu4NktCK98/PkPCluTA+uRHS7uvMXa/Z2WLPE8TDsS/ybYtaOhfq8Wi745fO26wI8rNGaJlKsfFskcKWC5eDQ==" }, "craftimizer.simulator": { "type": "Project" diff --git a/Simulator/Actions/BaseBuffAction.cs b/Simulator/Actions/BaseBuffAction.cs index 02e5daa..88f7acd 100644 --- a/Simulator/Actions/BaseBuffAction.cs +++ b/Simulator/Actions/BaseBuffAction.cs @@ -21,9 +21,10 @@ internal abstract class BaseBuffAction( // Non-instanced properties public readonly EffectType Effect = effect; public readonly int Duration = duration; + private readonly int trueDuration = increasesStepCount ? duration + 1 : duration; public override void UseSuccess(Simulator s) => - s.AddEffect(Effect, Duration); + s.AddEffect(Effect, trueDuration); public override string GetTooltip(Simulator s, bool addUsability) { diff --git a/Simulator/Actions/FinalAppraisal.cs b/Simulator/Actions/FinalAppraisal.cs index 923cd3b..fa24b9f 100644 --- a/Simulator/Actions/FinalAppraisal.cs +++ b/Simulator/Actions/FinalAppraisal.cs @@ -2,7 +2,7 @@ namespace Craftimizer.Simulator.Actions; internal sealed class FinalAppraisal() : BaseBuffAction( ActionCategory.Other, 42, 19012, - EffectType.FinalAppraisal, duration: 4, + EffectType.FinalAppraisal, duration: 5, increasesStepCount: false, defaultCPCost: 1) { diff --git a/Simulator/Actions/HastyTouch.cs b/Simulator/Actions/HastyTouch.cs index b069407..7d959c9 100644 --- a/Simulator/Actions/HastyTouch.cs +++ b/Simulator/Actions/HastyTouch.cs @@ -8,5 +8,11 @@ internal sealed class HastyTouch() : BaseAction( defaultSuccessRate: 60 ) { + public override void UseSuccess(Simulator s) + { + base.UseSuccess(s); + if (s.Input.Stats.Level >= 96) + s.AddEffect(EffectType.Expedience, 1 + 1); + } } diff --git a/Simulator/Actions/MuscleMemory.cs b/Simulator/Actions/MuscleMemory.cs index fa72d54..e091175 100644 --- a/Simulator/Actions/MuscleMemory.cs +++ b/Simulator/Actions/MuscleMemory.cs @@ -14,6 +14,6 @@ internal sealed class MuscleMemory() : BaseAction( public override void UseSuccess(Simulator s) { base.UseSuccess(s); - s.AddEffect(EffectType.MuscleMemory, 5); + s.AddEffect(EffectType.MuscleMemory, 5 + 1); } } diff --git a/Simulator/Actions/QuickInnovation.cs b/Simulator/Actions/QuickInnovation.cs index c809487..23da43d 100644 --- a/Simulator/Actions/QuickInnovation.cs +++ b/Simulator/Actions/QuickInnovation.cs @@ -11,8 +11,8 @@ internal sealed class QuickInnovation() : BaseBuffAction( base.IsPossible(s) && s.Input.Stats.IsSpecialist && !s.ActionStates.UsedQuickInnovation; public override bool CouldUse(Simulator s) => - !s.ActionStates.UsedQuickInnovation; + !s.ActionStates.UsedQuickInnovation && !s.HasEffect(EffectType.Innovation); public override string GetTooltip(Simulator s, bool addUsability) => - $"{GetBaseTooltip(s, addUsability)}Specialist Only\n"; + $"{base.GetTooltip(s, addUsability)}Specialist Only\n"; } diff --git a/Simulator/Effects.cs b/Simulator/Effects.cs index 0bea88c..41f21b9 100644 --- a/Simulator/Effects.cs +++ b/Simulator/Effects.cs @@ -16,8 +16,8 @@ public record struct Effects public byte WasteNot2; public byte MuscleMemory; public byte Manipulation; - public bool Expedience; - public bool TrainedPerfection; + public byte Expedience; + public byte TrainedPerfection; public bool HeartAndSoul; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -54,10 +54,10 @@ public record struct Effects Manipulation = duration; break; case EffectType.Expedience: - Expedience = duration != 0; + Expedience = duration; break; case EffectType.TrainedPerfection: - TrainedPerfection = duration != 0; + TrainedPerfection = duration; break; case EffectType.HeartAndSoul: HeartAndSoul = duration != 0; @@ -86,8 +86,8 @@ public record struct Effects EffectType.WasteNot2 => WasteNot2, EffectType.MuscleMemory => MuscleMemory, EffectType.Manipulation => Manipulation, - EffectType.Expedience => (byte)(Expedience ? 1 : 0), - EffectType.TrainedPerfection => (byte)(TrainedPerfection ? 1 : 0), + EffectType.Expedience => Expedience, + EffectType.TrainedPerfection => TrainedPerfection, EffectType.HeartAndSoul => (byte)(HeartAndSoul ? 1 : 0), _ => 0 }; @@ -127,8 +127,9 @@ public record struct Effects MuscleMemory--; if (Manipulation > 0) Manipulation--; - - Expedience = false; - TrainedPerfection = false; + if (Expedience > 0) + Expedience--; + if (TrainedPerfection > 0) + TrainedPerfection--; } } diff --git a/Simulator/Simulator.cs b/Simulator/Simulator.cs index 74c4a36..01f10a5 100644 --- a/Simulator/Simulator.cs +++ b/Simulator/Simulator.cs @@ -105,9 +105,6 @@ public class Simulator if (Condition == Condition.Primed) duration += 2; - // Duration will be decreased in the next step, so we need to add 1 - duration++; - ActiveEffects.SetDuration(effect, (byte)duration); }