Compare commits

...

10 Commits

Author SHA1 Message Date
JonKazama-Hellion 19c7c784f8 Add Hellion fork README, NOTICE, and COPYRIGHT
Build / build (push) Failing after 1m45s
Build / bench (push) Has been cancelled
Initial Hellion Forge documentation for the Craftimizer fork.

- Replace stub README with full project page (badges, fork scope table,
  tech stack, build instructions, project status, license block, FFXIV
  disclaimer, Hellion Forge footer)
- Add NOTICE.md with acknowledgement to Asriel Camora as the upstream
  author, direct word on fork intent, scope of changes, contact path,
  and explicit non-upstreaming rationale
- Add COPYRIGHT with dual-holder source code block (Asriel 2023 +
  Hellion Online Media 2026 for the SDK 15 maintenance), visual asset
  block (Hellion Forge logo by Florian Eck, all-rights-reserved), and
  bundled binary attribution (Raphael solver)
- Drop in the Hellion Forge logo under docs/images/

LICENSE remains unchanged — Asriel Camora's original MIT notice is
mandatory under MIT clause 3.
2026-05-26 19:45:24 +02:00
JonKazama-Hellion 531b103e8e Merge branch 'feature/dalamud-sdk-15-bump' 2026-05-26 19:35:53 +02:00
JonKazama-Hellion 8d6b603963 Bump Dalamud SDK 14.0.1 → 15.0.0 for FFXIV 7.5 API compatibility
- Update Dalamud.NET.Sdk version in csproj
- Regenerate packages.lock.json against SDK 15
- Migrate FFXIVClientStructs.FFXIV.Component.GUI.ValueType → AtkValueType
  (SynthesisValues.cs)
- Introduce local IEndObject interface in ImRaii2.cs (Dalamud's nested
  ImRaii.IEndObject was removed in SDK 15)
- Switch direct Dalamud ImRaii returns to typed disposables
  (ImRaii.TabItemDisposable, ImRaii.ColorDisposable)
- Replace `if (!panel)` / `if (plot)` with `.Success` checks for the
  local IEndObject helpers
- Fix ref-bool lifetime issue in Settings.TabItem by using the
  ImRaii.TabItem(label, flags) overload
2026-05-26 19:35:42 +02:00
Asriel Camora be349a29a4 Version 2.9.1.1
Signed-off-by: Asriel Camora <asriel@camora.dev>
2026-01-03 09:52:17 -08:00
Asriel Camora 9b69d1bc2a Use MinVer for versioning
Signed-off-by: Asriel Camora <asriel@camora.dev>
2026-01-03 08:02:45 -08:00
Asriel Camora e800bc4c75 Remove redundant check
Signed-off-by: Asriel Camora <asriel@camora.dev>
2026-01-03 07:56:07 -08:00
Asriel fdb31b5720 Merge pull request #58 from Narzaal/fix/requiredquality
fix: RequiredQuality for non expert recipes
2026-01-03 07:54:48 -08:00
Asriel Camora f26d958a5c Update Rapahel.Net
Signed-off-by: Asriel Camora <asriel@camora.dev>
2026-01-03 07:53:47 -08:00
Asriel Camora a041fc6ebf Update for 7.4 2025-12-21 23:55:42 -08:00
Narzaal 88a1be2738 Update RecipeData.cs
Allow quality calculation for recipes when RequiredQuality > 0 but not expert
2025-10-20 11:08:20 +02:00
27 changed files with 375 additions and 101 deletions
+5 -5
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -17,10 +17,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" /> <PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.14.0" /> <PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.15.8" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.14.0" /> <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.8" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.199"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.264">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
+53
View File
@@ -0,0 +1,53 @@
Craftimizer — Hellion fork of the FFXIV crafting plugin by Asriel Camora
═══════════════════════════════════════════════════════════════════
Source code
═══════════════════════════════════════════════════════════════════
Copyright (c) 2023 Asriel Camora
Original author of Craftimizer (https://github.com/WorkingRobot/Craftimizer).
The entire architecture, simulator, solver, recipe data layer,
synthesis hooks, macro engine, and every UI window are Asriel's
work. This fork would not exist without it.
Copyright (c) 2026 Hellion Online Media
Hellion fork maintenance: Dalamud SDK 14 → 15 migration for the
FFXIV 7.5 / Dalamud API 15 cycle. Scope: the ValueType → AtkValueType
rename in FFXIVClientStructs, the local IEndObject interface that
replaces the removed Dalamud ImRaii.IEndObject, the typed ImRaii
disposable returns (TabItemDisposable, ColorDisposable), and the
ImRaii.TabItem ref-bool lifetime fix. No functional changes.
Source code is licensed under the MIT License. The full Licence text
lives in the LICENSE file at the root of this repository.
═══════════════════════════════════════════════════════════════════
Visual assets
═══════════════════════════════════════════════════════════════════
Copyright (c) 2026 Florian Eck
Designer of the Hellion Forge logo (docs/images/hellion-forge.png).
Exclusive usage and marketing rights licensed to Hellion Online
Media. This asset is NOT covered by the MIT source code licence
above and may not be reused, modified, or redistributed without
separate permission from the copyright holder.
Copyright (c) 2023 Asriel Camora
Designer of the Craftimizer plugin icon (icon.png), the embedded
graphics (Craftimizer/Graphics/*.png), and the documentation
screenshots (Images/*.png). Asset reuse follows the MIT Licence
above.
═══════════════════════════════════════════════════════════════════
Bundled binary assets
═══════════════════════════════════════════════════════════════════
Raphael solver (Craftimizer/raphael_bindings.dll, Raphael.Net.dll)
Upstream Rust + .NET binding crate bundled as a pre-built binary
by the original Craftimizer build. Licensing follows the upstream
Raphael project; see the upstream Craftimizer repository for the
attribution chain.
═══════════════════════════════════════════════════════════════════
Acknowledgements directed at the upstream author live in NOTICE.md.
+4 -4
View File
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Dalamud.NET.Sdk/13.0.0"> <Project Sdk="Dalamud.NET.Sdk/15.0.0">
<PropertyGroup> <PropertyGroup>
<Authors>Asriel Camora</Authors> <Authors>Asriel Camora</Authors>
<Version>2.8.0.0</Version> <Version>2.9.1.1</Version>
<PackageProjectUrl>https://github.com/WorkingRobot/Craftimizer.git</PackageProjectUrl> <PackageProjectUrl>https://github.com/WorkingRobot/Craftimizer.git</PackageProjectUrl>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0-windows7.0</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -33,7 +33,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MathNet.Numerics" Version="5.0.0" /> <PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.199"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.264">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
+1 -1
View File
@@ -321,7 +321,7 @@ internal static class ImGuiUtils
using var fill = ImRaii2.PushColor(ImPlotCol.Fill, Vector4.One.WithAlpha(.5f)); using var fill = ImRaii2.PushColor(ImPlotCol.Fill, Vector4.One.WithAlpha(.5f));
using var plot = ImRaii2.Plot("##violin", size, ImPlotFlags.CanvasOnly | ImPlotFlags.NoInputs | ImPlotFlags.NoChild | ImPlotFlags.NoFrame); using var plot = ImRaii2.Plot("##violin", size, ImPlotFlags.CanvasOnly | ImPlotFlags.NoInputs | ImPlotFlags.NoChild | ImPlotFlags.NoFrame);
if (plot) if (plot.Success)
{ {
ImPlot.SetupAxes([], [], ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations | ImPlotAxisFlags.AutoFit); ImPlot.SetupAxes([], [], ImPlotAxisFlags.NoDecorations, ImPlotAxisFlags.NoDecorations | ImPlotAxisFlags.AutoFit);
ImPlot.SetupAxisLimits(ImAxis.X1, data.Min, data.Max, ImPlotCond.Always); ImPlot.SetupAxisLimits(ImAxis.X1, data.Min, data.Max, ImPlotCond.Always);
+13 -8
View File
@@ -6,9 +6,14 @@ using System.Numerics;
namespace Craftimizer.Plugin; namespace Craftimizer.Plugin;
public interface IEndObject : IDisposable
{
bool Success { get; }
}
public static class ImRaii2 public static class ImRaii2
{ {
private struct EndUnconditionally(Action endAction, bool success) : ImRaii.IEndObject, IDisposable private struct EndUnconditionally(Action endAction, bool success) : IEndObject
{ {
private Action EndAction { get; } = endAction; private Action EndAction { get; } = endAction;
@@ -26,7 +31,7 @@ public static class ImRaii2
} }
} }
private struct EndConditionally(Action endAction, bool success) : ImRaii.IEndObject, IDisposable private struct EndConditionally(Action endAction, bool success) : IEndObject
{ {
public bool Success { get; } = success; public bool Success { get; } = success;
@@ -48,36 +53,36 @@ public static class ImRaii2
} }
} }
public static ImRaii.IEndObject GroupPanel(string name, float width, out float internalWidth) public static IEndObject GroupPanel(string name, float width, out float internalWidth)
{ {
internalWidth = ImGuiUtils.BeginGroupPanel(name, width); internalWidth = ImGuiUtils.BeginGroupPanel(name, width);
return new EndUnconditionally(ImGuiUtils.EndGroupPanel, true); return new EndUnconditionally(ImGuiUtils.EndGroupPanel, true);
} }
public static ImRaii.IEndObject Plot(string title_id, Vector2 size, ImPlotFlags flags) public static IEndObject Plot(string title_id, Vector2 size, ImPlotFlags flags)
{ {
return new EndConditionally(new Action(ImPlot.EndPlot), ImPlot.BeginPlot(title_id, size, flags)); return new EndConditionally(new Action(ImPlot.EndPlot), ImPlot.BeginPlot(title_id, size, flags));
} }
public static ImRaii.IEndObject PushStyle(ImPlotStyleVar idx, Vector2 val) public static IEndObject PushStyle(ImPlotStyleVar idx, Vector2 val)
{ {
ImPlot.PushStyleVar(idx, val); ImPlot.PushStyleVar(idx, val);
return new EndUnconditionally(ImPlot.PopStyleVar, true); return new EndUnconditionally(ImPlot.PopStyleVar, true);
} }
public static ImRaii.IEndObject PushStyle(ImPlotStyleVar idx, float val) public static IEndObject PushStyle(ImPlotStyleVar idx, float val)
{ {
ImPlot.PushStyleVar(idx, val); ImPlot.PushStyleVar(idx, val);
return new EndUnconditionally(ImPlot.PopStyleVar, true); return new EndUnconditionally(ImPlot.PopStyleVar, true);
} }
public static ImRaii.IEndObject PushColor(ImPlotCol idx, Vector4 col) public static IEndObject PushColor(ImPlotCol idx, Vector4 col)
{ {
ImPlot.PushStyleColor(idx, col); ImPlot.PushStyleColor(idx, col);
return new EndUnconditionally(ImPlot.PopStyleColor, true); return new EndUnconditionally(ImPlot.PopStyleColor, true);
} }
public static ImRaii.IEndObject TextWrapPos(float wrap_local_pos_x) public static IEndObject TextWrapPos(float wrap_local_pos_x)
{ {
ImGui.PushTextWrapPos(wrap_local_pos_x); ImGui.PushTextWrapPos(wrap_local_pos_x);
return new EndUnconditionally(ImGui.PopTextWrapPos, true); return new EndUnconditionally(ImGui.PopTextWrapPos, true);
+4 -4
View File
@@ -75,7 +75,7 @@ public sealed class Plugin : IDalamudPlugin
var editorWindow = (EditorWindow?.IsOpen ?? false) ? EditorWindow : null; var editorWindow = (EditorWindow?.IsOpen ?? false) ? EditorWindow : null;
var recipeData = editorWindow?.RecipeData ?? Service.Plugin.RecipeNoteWindow.RecipeData; var recipeData = editorWindow?.RecipeData ?? Service.Plugin.RecipeNoteWindow.RecipeData;
var characterStats = editorWindow?.CharacterStats ?? Service.Plugin.RecipeNoteWindow.CharacterStats; var characterStats = editorWindow?.CharacterStats ?? Service.Plugin.RecipeNoteWindow.CharacterStats;
var buffs = editorWindow?.Buffs ?? (RecipeNoteWindow.CharacterStats != null ? new(Service.ClientState.LocalPlayer?.StatusList) : null); var buffs = editorWindow?.Buffs ?? (RecipeNoteWindow.CharacterStats != null ? new(Service.Objects.LocalPlayer?.StatusList) : null);
return (characterStats, recipeData, buffs); return (characterStats, recipeData, buffs);
} }
@@ -143,7 +143,7 @@ public sealed class Plugin : IDalamudPlugin
ListWindow.BringToFront(); ListWindow.BringToFront();
} }
public void OpenCraftingLog() public static void OpenCraftingLog()
{ {
Chat.SendMessage("/craftinglog"); Chat.SendMessage("/craftinglog");
} }
@@ -154,7 +154,7 @@ public sealed class Plugin : IDalamudPlugin
ClipboardWindow = new(macros); ClipboardWindow = new(macros);
} }
public IActiveNotification DisplaySolverWarning(string text) => public static IActiveNotification DisplaySolverWarning(string text) =>
DisplayNotification(new() DisplayNotification(new()
{ {
Content = text, Content = text,
@@ -162,7 +162,7 @@ public sealed class Plugin : IDalamudPlugin
Type = NotificationType.Warning Type = NotificationType.Warning
}); });
public IActiveNotification DisplayNotification(Notification notification) public static IActiveNotification DisplayNotification(Notification notification)
{ {
var ret = Service.NotificationManager.AddNotification(notification); var ret = Service.NotificationManager.AddNotification(notification);
// ret.SetIconTexture(Icon.RentAsync().ContinueWith(t => (IDalamudTextureWrap?)t)); // ret.SetIconTexture(Icon.RentAsync().ContinueWith(t => (IDalamudTextureWrap?)t));
+1 -1
View File
@@ -45,7 +45,7 @@ internal static class DynamicBars
defaultSize); defaultSize);
}); });
private static ImRaii.Color? PushCollectableColor(this in BarData bar, float collectability, bool colorUnmetThreshold = true) private static ImRaii.ColorDisposable? PushCollectableColor(this in BarData bar, float collectability, bool colorUnmetThreshold = true)
{ {
if (bar.Collectability is not { } collectabilities) if (bar.Collectability is not { } collectabilities)
return null; return null;
+4 -4
View File
@@ -33,7 +33,7 @@ public static class FoodStatus
if (item.ItemAction.ValueNullable is not { } itemAction) if (item.ItemAction.ValueNullable is not { } itemAction)
continue; continue;
if (itemAction.Type is not (844 or 845 or 846)) if (itemAction.Action.RowId is not (844 or 845 or 846))
continue; continue;
if (LuminaSheets.ItemFoodSheet.GetRowOrDefault(itemAction.Data[1]) is not { } itemFood) if (LuminaSheets.ItemFoodSheet.GetRowOrDefault(itemAction.Data[1]) is not { } itemFood)
@@ -66,12 +66,12 @@ public static class FoodStatus
lut.TryAdd(itemFood.RowId, item.RowId); lut.TryAdd(itemFood.RowId, item.RowId);
} }
ItemFoodToItemLUT = lut.ToFrozenDictionary(); ItemFoodToItemLUT = lut.ToFrozenDictionary();
FoodItems = foods.ToFrozenDictionary(); FoodItems = foods.ToFrozenDictionary();
MedicineItems = medicines.ToFrozenDictionary(); MedicineItems = medicines.ToFrozenDictionary();
FoodOrder = FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key).ToImmutableArray(); FoodOrder = [.. FoodItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key)];
MedicineOrder = MedicineItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key).ToImmutableArray(); MedicineOrder = [.. MedicineItems.OrderByDescending(a => a.Value.Item.LevelItem.RowId).Select(a => a.Key)];
} }
public static void Initialize() { } public static void Initialize() { }
+2 -2
View File
@@ -37,7 +37,7 @@ public sealed unsafe class Hooks : IDisposable
var ret = UseActionHook.Original(manager, actionType, actionId, targetId, extraParam, mode, comboRouteId, optOutAreaTargeted); var ret = UseActionHook.Original(manager, actionType, actionId, targetId, extraParam, mode, comboRouteId, optOutAreaTargeted);
if (canCast && ret && actionType is CSActionType.CraftAction or CSActionType.Action) if (canCast && ret && actionType is CSActionType.CraftAction or CSActionType.Action)
{ {
var classJob = ClassJobUtils.GetClassJobFromIdx((byte)(Service.ClientState.LocalPlayer?.ClassJob.RowId ?? 0)); var classJob = ClassJobUtils.GetClassJobFromIdx((byte)(Service.Objects.LocalPlayer?.ClassJob.RowId ?? 0));
if (classJob != null) if (classJob != null)
{ {
var simActionType = ActionUtils.GetActionTypeFromId(actionId, classJob.Value, actionType == CSActionType.CraftAction); var simActionType = ActionUtils.GetActionTypeFromId(actionId, classJob.Value, actionType == CSActionType.CraftAction);
@@ -75,7 +75,7 @@ public sealed unsafe class Hooks : IDisposable
if (actionType is not (CSActionType.CraftAction or CSActionType.Action)) if (actionType is not (CSActionType.CraftAction or CSActionType.Action))
return ret; return ret;
var jobId = Service.ClientState.LocalPlayer?.ClassJob.RowId; var jobId = Service.Objects.LocalPlayer?.ClassJob.RowId;
if (jobId == null) if (jobId == null)
return ret; return ret;
+1 -1
View File
@@ -26,7 +26,7 @@ public sealed class Ipc
if (prop.GetMethod is not { } getMethod) if (prop.GetMethod is not { } getMethod)
throw new InvalidOperationException("Property must have a getter"); throw new InvalidOperationException("Property must have a getter");
if (getMethod.GetCustomAttribute<CompilerGeneratedAttribute>() is null) if (!getMethod.IsDefined<CompilerGeneratedAttribute>())
throw new InvalidOperationException("Property must have an auto getter"); throw new InvalidOperationException("Property must have an auto getter");
var type = prop.PropertyType; var type = prop.PropertyType;
+7 -7
View File
@@ -20,7 +20,7 @@ public static class MacroCopy
{ {
if (actions.Count == 0) if (actions.Count == 0)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = "Cannot copy an empty macro.", Content = "Cannot copy an empty macro.",
MinimizedText = "Cannot copy empty macro", MinimizedText = "Cannot copy empty macro",
@@ -152,7 +152,7 @@ public static class MacroCopy
if (config.ShowCopiedMessage) if (config.ShowCopiedMessage)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = i > 1 ? "Copied macro to User Macros." : $"Copied {i} macros to User Macros.", Content = i > 1 ? "Copied macro to User Macros." : $"Copied {i} macros to User Macros.",
MinimizedText = i > 1 ? "Copied macro" : $"Copied {i} macros", MinimizedText = i > 1 ? "Copied macro" : $"Copied {i} macros",
@@ -164,7 +164,7 @@ public static class MacroCopy
{ {
Service.Plugin.OpenMacroClipboard(macros); Service.Plugin.OpenMacroClipboard(macros);
var rest = macros.Count - i; var rest = macros.Count - i;
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = $"Couldn't copy {rest} macro{(rest == 1 ? "" : "s")}, so a window was opened with all of them.", Content = $"Couldn't copy {rest} macro{(rest == 1 ? "" : "s")}, so a window was opened with all of them.",
Minimized = false, Minimized = false,
@@ -201,7 +201,7 @@ public static class MacroCopy
ImGui.SetClipboardText(string.Join(Environment.NewLine + Environment.NewLine, macros)); ImGui.SetClipboardText(string.Join(Environment.NewLine + Environment.NewLine, macros));
if (Service.Configuration.MacroCopy.ShowCopiedMessage) if (Service.Configuration.MacroCopy.ShowCopiedMessage)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = macros.Count == 1 ? "Copied macro to clipboard." : $"Copied {macros.Count} macros to clipboard.", Content = macros.Count == 1 ? "Copied macro to clipboard." : $"Copied {macros.Count} macros to clipboard.",
MinimizedText = macros.Count == 1 ? "Copied macro" : $"Copied {macros.Count} macros", MinimizedText = macros.Count == 1 ? "Copied macro" : $"Copied {macros.Count} macros",
@@ -215,7 +215,7 @@ public static class MacroCopy
{ {
if (!Service.Ipc.MacroMateIsAvailable()) if (!Service.Ipc.MacroMateIsAvailable())
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = "Please check if it installed and enabled.", Content = "Please check if it installed and enabled.",
MinimizedText = "Macro Mate is unavailable", MinimizedText = "Macro Mate is unavailable",
@@ -232,7 +232,7 @@ public static class MacroCopy
var (isValidParent, parentError) = Service.Ipc.MacroMateValidateGroupPath(parentPath); var (isValidParent, parentError) = Service.Ipc.MacroMateValidateGroupPath(parentPath);
if (!isValidParent) if (!isValidParent)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = parentError!, Content = parentError!,
MinimizedText = parentError, MinimizedText = parentError,
@@ -246,7 +246,7 @@ public static class MacroCopy
if (Service.Configuration.MacroCopy.ShowCopiedMessage) if (Service.Configuration.MacroCopy.ShowCopiedMessage)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = "Copied macro to Macro Mate.", Content = "Copied macro to Macro Mate.",
MinimizedText = "Copied macro", MinimizedText = "Copied macro",
+1 -1
View File
@@ -47,7 +47,7 @@ public sealed record RecipeData
ClassJobLevel = Table.ClassJobLevel, ClassJobLevel = Table.ClassJobLevel,
ConditionsFlag = Table.ConditionsFlag, ConditionsFlag = Table.ConditionsFlag,
MaxDurability = (Recipe.MaxAdjustableJobLevel.RowId != 0 ? 80 : Table.Durability) * Recipe.DurabilityFactor / 100, MaxDurability = (Recipe.MaxAdjustableJobLevel.RowId != 0 ? 80 : Table.Durability) * Recipe.DurabilityFactor / 100,
MaxQuality = (Recipe.CanHq || Recipe.IsExpert) ? (int)Table.Quality * Recipe.QualityFactor / 100 : 0, MaxQuality = (Recipe.CanHq || Recipe.RequiredQuality > 0) ? (int)Table.Quality * Recipe.QualityFactor / 100 : 0,
MaxProgress = Table.Difficulty * Recipe.DifficultyFactor / 100, MaxProgress = Table.Difficulty * Recipe.DifficultyFactor / 100,
QualityModifier = Table.QualityModifier, QualityModifier = Table.QualityModifier,
QualityDivider = Table.QualityDivider, QualityDivider = Table.QualityDivider,
+1 -1
View File
@@ -4,7 +4,7 @@ using Dalamud.Memory;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using System; using System;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.AtkValueType;
namespace Craftimizer.Utils; namespace Craftimizer.Utils;
+1 -1
View File
@@ -58,7 +58,7 @@ public sealed class MacroClipboard : Window, IDisposable
ImGui.SetClipboardText(macro); ImGui.SetClipboardText(macro);
if (Service.Configuration.MacroCopy.ShowCopiedMessage) if (Service.Configuration.MacroCopy.ShowCopiedMessage)
{ {
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = Macros.Count == 1 ? "Copied macro to clipboard." : $"Copied macro {idx + 1} to clipboard.", Content = Macros.Count == 1 ? "Copied macro to clipboard." : $"Copied macro {idx + 1} to clipboard.",
MinimizedText = Macros.Count == 1 ? "Copied macro" : $"Copied macro {idx + 1}", MinimizedText = Macros.Count == 1 ? "Copied macro" : $"Copied macro {idx + 1}",
+5 -5
View File
@@ -1008,13 +1008,13 @@ public sealed class MacroEditor : Window, IDisposable
} }
private const int MAX_LEVEL = 100; private const int MAX_LEVEL = 100;
private float GetLevelEntryWidth() private static float GetLevelEntryWidth()
{ {
var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + ImGui.GetStyle().FramePadding.X * 2 + 5; var levelTextWidth = ImGui.CalcTextSize(SqText.ToLevelString(MAX_LEVEL)).X + ImGui.GetStyle().FramePadding.X * 2 + 5;
return ImGui.CalcTextSize(SqText.LevelPrefix.ToIconString()).X + 5 + levelTextWidth; return ImGui.CalcTextSize(SqText.LevelPrefix.ToIconString()).X + 5 + levelTextWidth;
} }
private bool DrawLevelEntry(ref int level) private static bool DrawLevelEntry(ref int level)
{ {
static int LevelInputCallback(ImGuiInputTextCallbackDataPtr data) static int LevelInputCallback(ImGuiInputTextCallbackDataPtr data)
{ {
@@ -1570,7 +1570,7 @@ public sealed class MacroEditor : Window, IDisposable
foreach (var action in parsedActions) foreach (var action in parsedActions)
AddStep(action); AddStep(action);
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = $"Imported macro with {parsedActions.Count} step{(parsedActions.Count != 1 ? "s" : "")}", Content = $"Imported macro with {parsedActions.Count} step{(parsedActions.Count != 1 ? "s" : "")}",
MinimizedText = $"Imported {parsedActions.Count} step macro", MinimizedText = $"Imported {parsedActions.Count} step macro",
@@ -1626,7 +1626,7 @@ public sealed class MacroEditor : Window, IDisposable
Macro.Clear(); Macro.Clear();
foreach (var action in actions) foreach (var action in actions)
AddStep(action); AddStep(action);
Service.Plugin.DisplayNotification(new() Plugin.Plugin.DisplayNotification(new()
{ {
Content = $"Imported macro \"{name}\"", Content = $"Imported macro \"{name}\"",
Title = "Macro Imported", Title = "Macro Imported",
@@ -1677,7 +1677,7 @@ public sealed class MacroEditor : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t); solver.OnWarn += t => Plugin.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += a => Macro.Enqueue(a); solver.OnNewAction += a => Macro.Enqueue(a);
solver.OnSuggestSolution += a => Macro.EnqueueEphemeral(a.Actions); solver.OnSuggestSolution += a => Macro.EnqueueEphemeral(a.Actions);
SolverObject = solver; SolverObject = solver;
+4 -4
View File
@@ -23,7 +23,7 @@ public sealed class MacroList : Window, IDisposable
public CharacterStats? CharacterStats { get; private set; } public CharacterStats? CharacterStats { get; private set; }
public RecipeData? RecipeData { get; private set; } public RecipeData? RecipeData { get; private set; }
private IReadOnlyList<Macro> Macros => Service.Configuration.Macros; private static IReadOnlyList<Macro> Macros => Service.Configuration.Macros;
private Dictionary<Macro, SimulationState> MacroStateCache { get; } = []; private Dictionary<Macro, SimulationState> MacroStateCache { get; } = [];
public MacroList() : base("Craftimizer Macro List", WindowFlags, false) public MacroList() : base("Craftimizer Macro List", WindowFlags, false)
@@ -60,7 +60,7 @@ public sealed class MacroList : Window, IDisposable
public override bool DrawConditions() public override bool DrawConditions()
{ {
return Service.ClientState.LocalPlayer != null; return Service.Objects.LocalPlayer != null;
} }
public override void PreDraw() public override void PreDraw()
@@ -129,7 +129,7 @@ public sealed class MacroList : Window, IDisposable
ImGuiUtils.TextCentered(text2); ImGuiUtils.TextCentered(text2);
ImGuiUtils.AlignCentered(buttonRowWidth); ImGuiUtils.AlignCentered(buttonRowWidth);
if (ImGui.Button(text3)) if (ImGui.Button(text3))
Service.Plugin.OpenCraftingLog(); Plugin.Plugin.OpenCraftingLog();
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button(text4)) if (ImGui.Button(text4))
OpenEditor(null); OpenEditor(null);
@@ -356,7 +356,7 @@ public sealed class MacroList : Window, IDisposable
sortedMacros = [.. query]; sortedMacros = [.. query];
} }
private void OpenEditor(Macro? macro) private static void OpenEditor(Macro? macro)
{ {
var stats = Service.Plugin.GetDefaultStats(); var stats = Service.Plugin.GetDefaultStats();
Service.Plugin.OpenMacroEditor(stats.Character, stats.Recipe, stats.Buffs, null, macro?.Actions ?? Enumerable.Empty<ActionType>(), macro != null ? (actions => { macro.ActionEnumerable = actions; Service.Configuration.Save(); }) : null); Service.Plugin.OpenMacroEditor(stats.Character, stats.Recipe, stats.Buffs, null, macro?.Actions ?? Enumerable.Empty<ActionType>(), macro != null ? (actions => { macro.ActionEnumerable = actions; Service.Configuration.Save(); }) : null);
+6 -6
View File
@@ -190,7 +190,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
private bool StatsChanged { get; set; } private bool StatsChanged { get; set; }
private bool CalculateShouldOpen() private bool CalculateShouldOpen()
{ {
if (Service.ClientState.LocalPlayer == null) if (Service.Objects.LocalPlayer == null)
return false; return false;
bool ShouldUseRecipeNote() bool ShouldUseRecipeNote()
@@ -476,7 +476,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
Service.Plugin.OpenMacroListWindow(); Service.Plugin.OpenMacroListWindow();
if (ImGui.Button("Open in Macro Editor", new(availWidth, 0))) if (ImGui.Button("Open in Macro Editor", new(availWidth, 0)))
Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), [], null); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), [], null);
} }
private void DrawCharacterStats() private void DrawCharacterStats()
@@ -810,7 +810,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
}; };
using var panel = ImRaii2.GroupPanel(panelTitle, panelWidth, out _); using var panel = ImRaii2.GroupPanel(panelTitle, panelWidth, out _);
if (!panel) if (!panel.Success)
return; return;
var stepsAvailWidthOffset = ImGui.GetContentRegionAvail().X - panelWidth; var stepsAvailWidthOffset = ImGui.GetContentRegionAvail().X - panelWidth;
@@ -1031,7 +1031,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
ImGui.TableNextColumn(); ImGui.TableNextColumn();
{ {
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Edit, miniRowHeight))
Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), actions, state.MacroEditorSetter); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), CalculateIngredientHqCounts(), actions, state.MacroEditorSetter);
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
ImGuiUtils.Tooltip("Open in Macro Editor"); ImGuiUtils.Tooltip("Open in Macro Editor");
if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight)) if (ImGuiUtils.IconButtonSquare(FontAwesomeIcon.Paste, miniRowHeight))
@@ -1125,7 +1125,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
var statusRequired = RecipeData.Recipe.StatusRequired; var statusRequired = RecipeData.Recipe.StatusRequired;
if (statusRequired.RowId != 0 && statusRequired.IsValid) if (statusRequired.RowId != 0 && statusRequired.IsValid)
{ {
if (!Service.ClientState.LocalPlayer!.StatusList.Any(s => s.StatusId == statusRequired.RowId)) if (!Service.Objects.LocalPlayer!.StatusList.Any(s => s.StatusId == statusRequired.RowId))
return CraftableStatus.RequiredStatus; return CraftableStatus.RequiredStatus;
} }
@@ -1234,7 +1234,7 @@ public sealed unsafe class RecipeNote : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t); solver.OnWarn += t => Plugin.Plugin.DisplaySolverWarning(t);
BestMacroSolver = solver; BestMacroSolver = solver;
solver.Start(); solver.Start();
var solution = solver.GetTask().GetAwaiter().GetResult(); var solution = solver.GetTask().GetAwaiter().GetResult();
+13 -14
View File
@@ -50,14 +50,13 @@ public sealed class Settings : Window, IDisposable
SelectedTab = label; SelectedTab = label;
} }
private ImRaii.IEndObject TabItem(string label) private ImRaii.TabItemDisposable TabItem(string label)
{ {
var isSelected = string.Equals(SelectedTab, label, StringComparison.Ordinal); var isSelected = string.Equals(SelectedTab, label, StringComparison.Ordinal);
if (isSelected) if (isSelected)
{ {
SelectedTab = null; SelectedTab = null;
var open = true; return ImRaii.TabItem(label, ImGuiTabItemFlags.SetSelected);
return ImRaii.TabItem(label, ref open, ImGuiTabItemFlags.SetSelected);
} }
return ImRaii.TabItem(label); return ImRaii.TabItem(label);
} }
@@ -159,15 +158,15 @@ public sealed class Settings : Window, IDisposable
private static string GetAlgorithmTooltip(SolverAlgorithm algorithm) => private static string GetAlgorithmTooltip(SolverAlgorithm algorithm) =>
algorithm switch algorithm switch
{ {
SolverAlgorithm.Oneshot => "Run through all iterations and pick the best macro", SolverAlgorithm.Oneshot => "Run through all iterations and pick the best macro",
SolverAlgorithm.OneshotForked => "Oneshot, but using multiple solvers simultaneously", SolverAlgorithm.OneshotForked => "Oneshot, but using multiple solvers simultaneously",
SolverAlgorithm.Stepwise => "Run through all iterations and pick the next best step, " + SolverAlgorithm.Stepwise => "Run through all iterations and pick the next best step, " +
"and repeat using previous steps as a starting point", "and repeat using previous steps as a starting point",
SolverAlgorithm.StepwiseForked => "Stepwise, but using multiple solvers simultaneously", SolverAlgorithm.StepwiseForked => "Stepwise, but using multiple solvers simultaneously",
SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " + SolverAlgorithm.StepwiseGenetic => "Stepwise Forked, but the top N next best steps are " +
"selected from the solvers, and each one is equally " + "selected from the solvers, and each one is equally " +
"used as a starting point", "used as a starting point",
SolverAlgorithm.Raphael => "Finds the best solution, every time. This solver has " + SolverAlgorithm.Raphael => "Finds the best solution, every time. This solver has " +
"very different options compared to the rest, as it " + "very different options compared to the rest, as it " +
"is designed using an entirely different algorithm.", "is designed using an entirely different algorithm.",
_ => "Unknown" _ => "Unknown"
@@ -186,11 +185,11 @@ public sealed class Settings : Window, IDisposable
private static string GetCopyTypeTooltip(MacroCopyConfiguration.CopyType type) => private static string GetCopyTypeTooltip(MacroCopyConfiguration.CopyType type) =>
type switch type switch
{ {
MacroCopyConfiguration.CopyType.OpenWindow => "Open a dedicated window with all macros being copied. " + MacroCopyConfiguration.CopyType.OpenWindow => "Open a dedicated window with all macros being copied. " +
"Copy, view, and choose at your own leisure.", "Copy, view, and choose at your own leisure.",
MacroCopyConfiguration.CopyType.CopyToMacro => "Copy directly to the game's macro system.", MacroCopyConfiguration.CopyType.CopyToMacro => "Copy directly to the game's macro system.",
MacroCopyConfiguration.CopyType.CopyToClipboard => "Copy to your clipboard. Macros are separated by a blank line.", MacroCopyConfiguration.CopyType.CopyToClipboard => "Copy to your clipboard. Macros are separated by a blank line.",
MacroCopyConfiguration.CopyType.CopyToMacroMate => "Copy directly to a Macro Mate macro. Requires the Macro Mate plugin.", MacroCopyConfiguration.CopyType.CopyToMacroMate => "Copy directly to a Macro Mate macro. Requires the Macro Mate plugin.",
_ => "Unknown" _ => "Unknown"
}; };
@@ -653,7 +652,7 @@ public sealed class Settings : Window, IDisposable
else else
{ {
DrawOption( DrawOption(
"Quick Solve", "Backload Progress",
"Speeds up solve times. Backloads all Progress " + "Speeds up solve times. Backloads all Progress " +
"actions to the end of the rotation.", "actions to the end of the rotation.",
config.BackloadProgress, config.BackloadProgress,
+4 -4
View File
@@ -159,7 +159,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
private bool wasInCraftAction; private bool wasInCraftAction;
private bool CalculateShouldOpen() private bool CalculateShouldOpen()
{ {
if (Service.ClientState.LocalPlayer == null) if (Service.Objects.LocalPlayer == null)
return false; return false;
if (!Service.Configuration.EnableSynthHelper) if (!Service.Configuration.EnableSynthHelper)
@@ -486,7 +486,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
} }
if (ImGui.Button("Open in Macro Editor", new(-1, 0))) if (ImGui.Button("Open in Macro Editor", new(-1, 0)))
Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), null, [], null); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.Objects.LocalPlayer!.StatusList), null, [], null);
} }
public bool ExecuteNextAction() public bool ExecuteNextAction()
@@ -559,7 +559,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
private SimulationState GetCurrentState() private SimulationState GetCurrentState()
{ {
var player = Service.ClientState.LocalPlayer!; var player = Service.Objects.LocalPlayer!;
var values = new SynthesisValues(Addon); var values = new SynthesisValues(Addon);
var statusManager = ((Character*)player.Address)->GetStatusManager(); var statusManager = ((Character*)player.Address)->GetStatusManager();
@@ -649,7 +649,7 @@ public sealed unsafe class SynthHelper : Window, IDisposable
var solver = new Solver.Solver(config, state) { Token = token }; var solver = new Solver.Solver(config, state) { Token = token };
solver.OnLog += Log.Debug; solver.OnLog += Log.Debug;
solver.OnWarn += t => Service.Plugin.DisplaySolverWarning(t); solver.OnWarn += t => Plugin.Plugin.DisplaySolverWarning(t);
solver.OnNewAction += EnqueueAction; solver.OnNewAction += EnqueueAction;
SolverObject = solver; SolverObject = solver;
solver.Start(); solver.Start();
+19 -19
View File
@@ -1,18 +1,18 @@
{ {
"version": 1, "version": 1,
"dependencies": { "dependencies": {
"net9.0-windows7.0": { "net10.0-windows7.0": {
"DalamudPackager": { "DalamudPackager": {
"type": "Direct", "type": "Direct",
"requested": "[13.0.0, )", "requested": "[15.0.0, )",
"resolved": "13.0.0", "resolved": "15.0.0",
"contentHash": "Mb3cUDSK/vDPQ8gQIeuCw03EMYrej1B4J44a1AvIJ9C759p9XeqdU9Hg4WgOmlnlPe0G7ILTD32PKSUpkQNa8w==" "contentHash": "411vwC8/X8Z/sQ2TI6v3SvOn66xFPeOjFn3Zn+h0d3Ox2t1kFm66AhDvmx/qcMwVrR+Hidxj0dadpQ2dgyXMBQ=="
}, },
"DotNet.ReproducibleBuilds": { "DotNet.ReproducibleBuilds": {
"type": "Direct", "type": "Direct",
"requested": "[1.2.25, )", "requested": "[1.2.39, )",
"resolved": "1.2.25", "resolved": "1.2.39",
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg==" "contentHash": "fcFN01tDTIQqDuTwr1jUQK/geofiwjG5DycJQOnC72i1SsLAk1ELe+apBOuZ11UMQG8YKFZG1FgvjZPbqHyatg=="
}, },
"MathNet.Numerics": { "MathNet.Numerics": {
"type": "Direct", "type": "Direct",
@@ -22,22 +22,22 @@
}, },
"Meziantou.Analyzer": { "Meziantou.Analyzer": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.199, )", "requested": "[2.0.264, )",
"resolved": "2.0.199", "resolved": "2.0.264",
"contentHash": "y8oRrTLDBw1b10pWci/PnFoahdIMflNSlVheL9kzUylAASnoJPFyvuyaNXcrbOTNOEk1aMLFRr1mSX/xvYR15g==" "contentHash": "zRG13RDG446rZNdd/YjKRd4utpbjleRDUqNQSrX0etMnH8Rz9NBlXUpS5aR2ExoOokhNfkdOW8HpLzjLj5x0hQ=="
}, },
"DotNext": { "DotNext": {
"type": "Transitive", "type": "Transitive",
"resolved": "5.21.0", "resolved": "5.26.1",
"contentHash": "fU63OJVSDSsOl6adjNM8e5zmyhdZkX2ztvmSeW6lBjFdvFG8ZwMOrJ+L8Ih/2yKr0cuaV8PNwnhDrlS4MFf14A==", "contentHash": "rcy6Yrpb64B7qYm/+D+4sfBUzwX/IOGeJBYReDL8/TAIp8aZrZPtXx8nwkYjWCuakYn2tBppwefIM6pd/cOnMw==",
"dependencies": { "dependencies": {
"System.IO.Hashing": "8.0.0" "System.IO.Hashing": "8.0.0"
} }
}, },
"Raphael.Net": { "Raphael.Net": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.0", "resolved": "4.1.0",
"contentHash": "9yY+jR2gddw52HtShBL/JikQ4gZa8lxFYSUIi2y510HLsaK86iqtuRgrv8/akrHR66QRWEPtmHXyehW1hrmP9Q==" "contentHash": "KRkRUn5gdFwKMpZXtFC9W58lNnhSXQpvNmLaCn7f9Tbx92UhRfttC7/QqyWhjkD2u6L9YNIpNp3nxF6awEOntw=="
}, },
"System.IO.Hashing": { "System.IO.Hashing": {
"type": "Transitive", "type": "Transitive",
@@ -51,16 +51,16 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Craftimizer.Simulator": "[1.0.0, )", "Craftimizer.Simulator": "[1.0.0, )",
"DotNext": "[5.21.0, )", "DotNext": "[5.26.1, )",
"Raphael.Net": "[3.0.0, )" "Raphael.Net": "[4.1.0, )"
} }
} }
}, },
"net9.0-windows7.0/win-x64": { "net10.0-windows7.0/win-x64": {
"Raphael.Net": { "Raphael.Net": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.0", "resolved": "4.1.0",
"contentHash": "9yY+jR2gddw52HtShBL/JikQ4gZa8lxFYSUIi2y510HLsaK86iqtuRgrv8/akrHR66QRWEPtmHXyehW1hrmP9Q==" "contentHash": "KRkRUn5gdFwKMpZXtFC9W58lNnhSXQpvNmLaCn7f9Tbx92UhRfttC7/QqyWhjkD2u6L9YNIpNp3nxF6awEOntw=="
} }
} }
} }
+87
View File
@@ -0,0 +1,87 @@
# Notice
## Acknowledgements
This Craftimizer fork is built on
[Craftimizer](https://github.com/WorkingRobot/Craftimizer) by
**[Asriel Camora](https://github.com/WorkingRobot)**, who built and
maintained the plugin for years. The entire architecture, the crafting
simulator, the macro solver, the recipe data layer, the synthesis helper,
and every UI window come from Asriel's work. Without Craftimizer, this
fork would not exist.
If this fork is useful to you, the credit for that belongs in large
part to Asriel.
## A direct word to Asriel
Hi. I am Jon. I forked Craftimizer because the upstream `main` branch
had not received an update past FFXIV 7.4, and I wanted a working
crafting plugin for personal use that still loads on the current Dalamud
API. This is not a "do it better" fork. The opposite is true. I would
have happily kept using upstream if it had stayed current.
What this fork adds is purely a Dalamud SDK 14 → 15 migration cycle.
Concretely, three changes in `FFXIVClientStructs` and Dalamud's `ImRaii`
namespace were renamed or removed; this fork ports the affected call
sites to the new symbol names and adds a local `IEndObject` interface to
replace the nested one Dalamud removed. No new features, no design
departures, no rebranding of internal namespaces. Where I had to modify
your sources I kept the edits minimal, isolated to the lines the SDK 15
compiler refused, and revertible.
If you pick Craftimizer back up and ship an upstream SDK 15 update, this
fork folds back into a pure mirror and the recommendation will be to
switch back to your build.
If anything in this fork ever steps on something you would not be okay
with — attribution, naming, anything else — please reach out and I will
fix it. Genuinely.
## Why this fork exists
The upstream `main` last commit is "Update for 7.4" from late 2025. The
plugin is otherwise dormant: no SDK 15 branch, no public roadmap, no
recent issue activity from the maintainer. FFXIV 7.5 brought the Dalamud
API jump from level 14 to 15 in early 2026, and Craftimizer stopped
loading from then on. My personal crafting workflow depends on it, so I
took the maintenance burden on for a while.
This fork is maintained for personal and friend-circle use under Hellion
Forge. It is not a competing project and does not target the broader
Craftimizer user base.
## Why this fork is not upstreamed
I did not open a pull request because the upstream repository has been
quiet for months and there is no signal that maintenance bandwidth is
available on Asriel's side. A drive-by SDK-15-bump PR with no maintainer
to land it would sit open indefinitely and create the wrong impression
that the change has been reviewed. If upstream becomes active again and
wants the migration, the change set is small enough (+23 / -19 lines,
seven files) to merge by hand in minutes.
## Maintainer contact
If something in this fork causes problems, especially if it relates back
to upstream Craftimizer or to attribution:
- **Gitea Issues:**
[JonKazama-Hellion/Craftimizer/issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/Craftimizer/issues)
- **Discord:** `@j.j_kazama`
- **Email (business):** <kontakt@hellion-media.de>
I respond on weekdays during European business hours. For attribution
or takedown questions, email is the fastest path.
## Trademarks and naming
"Craftimizer" is the name Asriel chose for the upstream plugin. This
fork keeps the name as a reference to the origin and does not rebrand
the user-facing identity. The Hellion brand is mine.
---
Maintained under **Hellion Forge**, the modding and plugin line of
**Hellion Online Media** | Bad Harzburg |
[hellion-media.de](https://hellion-media.de)
+131 -2
View File
@@ -1,3 +1,132 @@
# Craftimizer # Craftimizer (Hellion Fork)
soon(tm) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Dalamud API](https://img.shields.io/badge/Dalamud-API_15-purple)](https://github.com/goatcorp/Dalamud)
[![.NET](https://img.shields.io/badge/.NET-10.0-512BD4)](https://dotnet.microsoft.com/)
[![FFXIV](https://img.shields.io/badge/FFXIV-7.5+-c3a37f)](https://www.finalfantasyxiv.com/)
[![Upstream](https://img.shields.io/badge/upstream-WorkingRobot%2FCraftimizer-blue)](https://github.com/WorkingRobot/Craftimizer)
<p align="center">
<img src="docs/images/hellion-forge.png" alt="Hellion Forge" width="180" />
</p>
**Version 2.9.1.1 (Hellion fork)** — a maintenance fork of
[Craftimizer](https://github.com/WorkingRobot/Craftimizer) by
[Asriel Camora](https://github.com/WorkingRobot), brought back to life on
Dalamud SDK 15 for FFXIV 7.5+.
Upstream Craftimizer received its last update for FFXIV 7.4 in late 2025 and
has been dormant since. With the Dalamud API jump from level 14 to 15 in
early 2026, the plugin stopped loading. This fork is a narrow API-compatibility
cycle that gets it back on its feet for personal and friend-circle use. No
features added, no design changes, no behavior departures from upstream. If
Asriel ships an official SDK 15 update upstream, this fork folds back into a
pure mirror and the recommendation will be to switch back.
## Acknowledgements
Every line of crafting logic, every solver heuristic, the entire simulator, the
recipe data layer, the synthesis hooks, and all UI windows are
**[Asriel Camora](https://github.com/WorkingRobot)**'s work. This fork only
unblocks the API path. Full acknowledgement in [NOTICE.md](NOTICE.md).
This fork is maintained under **Hellion Forge**, the modding and plugin line of
[Hellion Online Media](https://hellion-media.de).
---
## What this fork changes
| Area | Upstream (last 2.9.1.1) | This fork |
| ----------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------- |
| Dalamud SDK | 14.0.1 | **15.0.0** |
| Dalamud API Level | 14 (manifest unset, packager-inferred) | **15** (packager-set) |
| `FFXIVClientStructs.FFXIV.Component.GUI` type | `ValueType` | `AtkValueType` (upstream rename) |
| `Dalamud.Interface.Utility.Raii.ImRaii` nested | `IEndObject`, `Color` (removed in SDK15) | local `IEndObject` interface in `ImRaii2.cs`; typed `ImRaii.*Disposable` returns |
| `Settings.TabItem` ref-bool lifetime | `var open = true; TabItem(label, ref open, flags)` (rejected by SDK 15 escape analysis) | `TabItem(label, flags)` overload (no ref) |
Diff total: **+23 / 19 lines** across seven files. The change set is
intentionally minimal so a future upstream merge stays trivial.
---
## Tech Stack
| Category | Technology |
| ---------- | ----------------------------------------------------- |
| Platform | Dalamud Plugin (API Level 15) |
| Language | C# / .NET 10 (`net10.0-windows`) |
| Build | Dalamud.NET.Sdk 15.0.0 |
| UI | Dear ImGui via Dalamud bindings |
| Solver | Raphael (Rust crate, bundled as `raphael_bindings.dll`) |
| Toolchain | dotnet 10 SDK |
---
## Build
```bash
git clone ssh://git@gitea.hellion-forge.cloud:2222/JonKazama-Hellion/Craftimizer.git
cd Craftimizer
dotnet build Craftimizer.sln -c Release
```
The plugin DLL plus the manifest land in `Craftimizer/bin/x64/Release/`. Point
Dalamud's **Dev Plugin Locations** at that folder (`/xlsettings`
**Experimental**) to load it as a dev plugin.
---
## Project Status
**Experimental Hellion fork — personal-use only.** No distribution channel,
no custom repo, no release pipeline. This may change if the fork grows beyond
a single-user maintenance build, but for now: clone, build, dev-load.
If upstream resumes active maintenance, this fork archives.
---
## Community & Support
- Bug reports and questions:
[Gitea Issues](https://gitea.hellion-forge.cloud/JonKazama-Hellion/Craftimizer/issues)
- Discord DM: `@j.j_kazama`
- Email (business): <kontakt@hellion-media.de>
For anything that relates back to upstream Craftimizer or to attribution, see
the contact path in [NOTICE.md](NOTICE.md).
---
## License
MIT (same license as upstream Craftimizer). Full text in [LICENSE](LICENSE).
Copyright details with dual-holder block in [COPYRIGHT](COPYRIGHT). Personal
acknowledgement to the upstream author in [NOTICE.md](NOTICE.md).
© 2023 [Asriel Camora](https://github.com/WorkingRobot) for the original
Craftimizer plugin. © 2026 Hellion Online Media for the Dalamud SDK 15
fork-maintenance modifications.
### FFXIV Disclaimer
FINAL FANTASY XIV © SQUARE ENIX CO., LTD. All rights reserved. Craftimizer
and this fork are unofficial, fan-made plugins and are not affiliated with,
supported by, sponsored by, or approved by Square Enix.
---
## Project Documents
| Document | Contents |
| -------------------------- | -------------------------------------------------------------- |
| [`LICENSE`](LICENSE) | MIT licence full text (Asriel Camora original notice intact). |
| [`COPYRIGHT`](COPYRIGHT) | Dual-holder copyright block, visual asset attribution. |
| [`NOTICE.md`](NOTICE.md) | Acknowledgement to upstream author, scope of fork, contact. |
---
Maintained under **Hellion Forge**, the modding and plugin line of
**Hellion Online Media** | Bad Harzburg |
[hellion-media.de](https://hellion-media.de)
+2 -2
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
@@ -9,7 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.199"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.264">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
+4 -4
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
@@ -10,12 +10,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DotNext" Version="5.21.0" /> <PackageReference Include="DotNext" Version="5.26.1" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.199"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.264">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Raphael.Net" Version="3.0.0" /> <PackageReference Include="Raphael.Net" Version="4.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+1
View File
@@ -209,6 +209,7 @@ public sealed class Solver : IDisposable
{ {
Adversarial = Config.Adversarial, Adversarial = Config.Adversarial,
BackloadProgress = Config.BackloadProgress, BackloadProgress = Config.BackloadProgress,
AllowNonMaxQualitySolutions = true,
LogLevel = Raphael.LevelFilter.Debug, LogLevel = Raphael.LevelFilter.Debug,
ThreadCount = (ushort)Config.MaxThreadCount, ThreadCount = (ushort)Config.MaxThreadCount,
}; };
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB