Files
Craftimizer/Craftimizer/Utils/MacroCopy.cs
T
JonKazama-Hellion b598c03e9e Apply csharpier reflow across source tree
Reformats the entire Craftimizer source tree with dotnet csharpier 1.2.6
to match the Hellion Forge house style (matches what HellionChat enforces
in its pre-push pipeline). Pure whitespace + using-block sorting; no
semantic changes.

This is a one-time noisy commit. Future code edits in this fork should
land csharpier-clean because the pre-push hook (introduced in the next
commit) runs `dotnet csharpier check Craftimizer/` as Block C of the
preflight gate.

Trade-off acknowledged: this widens the merge gap with upstream
Craftimizer should Asriel ever resume maintenance. Given the upstream
has been dormant since FFXIV 7.4 and the fork is light-rename only
(internal namespaces unchanged), the marginal cost is acceptable.
2026-05-26 20:21:21 +02:00

296 lines
9.6 KiB
C#

using System;
using System.Collections.Generic;
using Craftimizer.Plugin;
using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.ImGuiNotification;
using FFXIVClientStructs.FFXIV.Client.System.Memory;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
namespace Craftimizer.Utils;
public static class MacroCopy
{
private const ClassJob DefaultJob = ClassJob.Carpenter;
private const int MacroSize = 15;
public static void Copy(IReadOnlyList<ActionType> actions)
{
if (actions.Count == 0)
{
Plugin.Plugin.DisplayNotification(
new()
{
Content = "Cannot copy an empty macro.",
MinimizedText = "Cannot copy empty macro",
Title = "Macro Not Copied",
Type = NotificationType.Error,
}
);
return;
}
var macros = GetMacros(actions, Service.Configuration.MacroCopy);
switch (Service.Configuration.MacroCopy.Type)
{
case MacroCopyConfiguration.CopyType.OpenWindow:
Service.Plugin.OpenMacroClipboard(macros);
break;
case MacroCopyConfiguration.CopyType.CopyToMacro:
CopyToMacro(macros);
break;
case MacroCopyConfiguration.CopyType.CopyToClipboard:
CopyToClipboard(macros);
break;
case MacroCopyConfiguration.CopyType.CopyToMacroMate:
CopyToMacroMate(macros[0]);
break;
}
}
private static List<string> GetMacros(
IReadOnlyList<ActionType> actions,
MacroCopyConfiguration config
)
{
var mustSplit =
(config.Type == MacroCopyConfiguration.CopyType.CopyToMacro || !config.CombineMacro)
&& config.Type != MacroCopyConfiguration.CopyType.CopyToMacroMate;
var macros = new List<string>();
var m = new List<string>();
for (var i = 0; i < actions.Count; ++i)
{
var a = actions[i];
var isLast = i == actions.Count - 1;
var isSecondLast = i == actions.Count - 2;
if (config.UseMacroLock && m.Count == 0)
m.Add("/mlock");
m.Add(GetActionCommand(a, config));
if (mustSplit && !isLast)
{
var endLine = GetEndCommand(macros.Count, false, config);
if (endLine != null && m.Count == MacroSize - 1)
{
if (!isSecondLast || config.ForceNotification)
m.Add(endLine);
}
}
if (mustSplit && m.Count == MacroSize)
{
macros.Add(string.Join(Environment.NewLine, m));
m.Clear();
}
}
if (m.Count != MacroSize && m.Count != 0)
{
if (GetEndCommand(macros.Count, true, config) is { } endLine)
m.Add(endLine);
}
if (m.Count != 0)
macros.Add(string.Join(Environment.NewLine, m));
return macros;
}
private static string GetActionCommand(ActionType action, MacroCopyConfiguration config)
{
var actionBase = action.Base();
if (actionBase is BaseComboAction)
throw new ArgumentException("Combo actions are not supported", nameof(action));
if (config.Type != MacroCopyConfiguration.CopyType.CopyToMacro && config.RemoveWaitTimes)
return $"/ac \"{action.GetName(DefaultJob)}\"";
else
return $"/ac \"{action.GetName(DefaultJob)}\" <wait.{actionBase.MacroWaitTime}>";
}
private static string? GetEndCommand(int macroIdx, bool isEnd, MacroCopyConfiguration config)
{
if (config.UseNextMacro && !isEnd)
{
if (config.Type == MacroCopyConfiguration.CopyType.CopyToMacro && config.CopyDown)
return $"/nextmacro down";
else
return $"/nextmacro";
}
if (config.AddNotification)
{
if (isEnd)
{
if (config.AddNotificationSound)
return $"/echo Craft complete! <se.{config.EndNotificationSound}>";
else
return $"/echo Craft complete!";
}
else
{
if (config.AddNotificationSound)
return $"/echo Macro #{macroIdx + 1} complete! <se.{config.IntermediateNotificationSound}>";
else
return $"/echo Macro #{macroIdx + 1} complete!";
}
}
return null;
}
private static void CopyToMacro(List<string> macros)
{
var config = Service.Configuration.MacroCopy;
int i,
macroIdx;
for (
i = 0, macroIdx = config.StartMacroIdx;
i < macros.Count && i < config.MaxMacroCount && macroIdx < 100;
i++, macroIdx += config.CopyDown ? 10 : 1
)
SetMacro(macroIdx, config.SharedMacro, macros[i], i + 1);
if (config.ShowCopiedMessage)
{
Plugin.Plugin.DisplayNotification(
new()
{
Content =
i > 1
? "Copied macro to User Macros."
: $"Copied {i} macros to User Macros.",
MinimizedText = i > 1 ? "Copied macro" : $"Copied {i} macros",
Title = "Macro Copied",
Type = NotificationType.Success,
}
);
}
if (i < macros.Count)
{
Service.Plugin.OpenMacroClipboard(macros);
var rest = macros.Count - i;
Plugin.Plugin.DisplayNotification(
new()
{
Content =
$"Couldn't copy {rest} macro{(rest == 1 ? "" : "s")}, so a window was opened with all of them.",
Minimized = false,
Title = "Macro Copied",
Type = NotificationType.Warning,
}
);
}
}
private static unsafe void SetMacro(int idx, bool isShared, string macroText, int macroIdx)
{
if (idx >= 100 || idx < 0)
throw new ArgumentOutOfRangeException(
nameof(idx),
"Macro index must be between 0 and 99"
);
var set = isShared ? 1u : 0u;
var module = RaptureMacroModule.Instance();
var macro = module->GetMacro(set, (uint)idx);
if (!macro->IsNotEmpty())
{
macro->Name.SetString($"Craftimizer Macro {macroIdx}");
macro->SetIcon((uint)(macroIdx > 10 ? 66161 : (66161 + macroIdx)));
}
var text = Utf8String.FromString(macroText.ReplaceLineEndings("\n"));
module->ReplaceMacroLines(macro, text);
text->Dtor();
IMemorySpace.Free(text);
RaptureHotbarModule.Instance()->ReloadMacroSlots((byte)set, (byte)idx);
}
private static void CopyToClipboard(List<string> macros)
{
ImGui.SetClipboardText(string.Join(Environment.NewLine + Environment.NewLine, macros));
if (Service.Configuration.MacroCopy.ShowCopiedMessage)
{
Plugin.Plugin.DisplayNotification(
new()
{
Content =
macros.Count == 1
? "Copied macro to clipboard."
: $"Copied {macros.Count} macros to clipboard.",
MinimizedText =
macros.Count == 1 ? "Copied macro" : $"Copied {macros.Count} macros",
Title = "Macro Copied",
Type = NotificationType.Success,
}
);
}
}
private static void CopyToMacroMate(string macro)
{
if (!Service.Ipc.MacroMateIsAvailable())
{
Plugin.Plugin.DisplayNotification(
new()
{
Content = "Please check if it installed and enabled.",
MinimizedText = "Macro Mate is unavailable",
Title = "Macro Mate Unavailable",
Type = NotificationType.Error,
}
);
return;
}
var parentPath = Service.Configuration.MacroCopy.MacroMateParent;
if (string.IsNullOrWhiteSpace(parentPath))
parentPath = "/";
var (isValidParent, parentError) = Service.Ipc.MacroMateValidateGroupPath(parentPath);
if (!isValidParent)
{
Plugin.Plugin.DisplayNotification(
new()
{
Content = parentError!,
MinimizedText = parentError,
Title = "Macro Mate Invalid Parent",
Type = NotificationType.Error,
}
);
return;
}
Service.Ipc.MacroMateCreateMacro(
Service.Configuration.MacroCopy.MacroMateName,
macro,
parentPath,
null
);
if (Service.Configuration.MacroCopy.ShowCopiedMessage)
{
Plugin.Plugin.DisplayNotification(
new()
{
Content = "Copied macro to Macro Mate.",
MinimizedText = "Copied macro",
Title = "Macro Copied",
Type = NotificationType.Success,
}
);
}
}
}