Ability ants :p

This commit is contained in:
Asriel Camora
2024-07-04 00:36:58 -07:00
parent 5093867971
commit ec60bcfdcf
5 changed files with 88 additions and 25 deletions
+2 -1
View File
@@ -181,8 +181,9 @@ public partial class Configuration
public bool SuggestMacroAutomatically { get; set; } public bool SuggestMacroAutomatically { get; set; }
public bool ShowCommunityMacros { get; set; } = true; public bool ShowCommunityMacros { get; set; } = true;
public bool SearchCommunityMacroAutomatically { get; set; } public bool SearchCommunityMacroAutomatically { get; set; }
public int SynthHelperStepCount { get; set; } = 5; public int SynthHelperStepCount { get; set; } = 3;
public bool SynthHelperDisplayOnlyFirstStep { get; set; } public bool SynthHelperDisplayOnlyFirstStep { get; set; }
public bool SynthHelperAbilityAnts { get; set; }
public bool PinSynthHelperToWindow { get; set; } = true; public bool PinSynthHelperToWindow { get; set; } = true;
public bool PinRecipeNoteToWindow { get; set; } = true; public bool PinRecipeNoteToWindow { get; set; } = true;
+1 -1
View File
@@ -113,7 +113,7 @@ public sealed class Plugin : IDalamudPlugin
[Command(name: "/craftaction", description: "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.")] [Command(name: "/craftaction", description: "Execute the suggested action in the synthesis helper. Can also be run inside a macro. This command is useful for controller players.")]
public void ExecuteSuggestedSynthHelperAction() => public void ExecuteSuggestedSynthHelperAction() =>
SynthHelperWindow.QueueSuggestedActionExecution(); SynthHelperWindow.ExecuteNextAction();
[Command(name: "/craftimizer", description: "Open the settings window.")] [Command(name: "/craftimizer", description: "Open the settings window.")]
private void OpenSettingsWindowForced() => private void OpenSettingsWindowForced() =>
+40 -1
View File
@@ -18,17 +18,24 @@ public sealed unsafe class Hooks : IDisposable
public readonly Hook<UseActionDelegate> UseActionHook = null!; public readonly Hook<UseActionDelegate> UseActionHook = null!;
public delegate byte IsActionHighlightedDelegate(ActionManager* manager, CSActionType actionType, uint actionId);
public readonly Hook<IsActionHighlightedDelegate> IsActionHighlightedHook = null!;
public Hooks() public Hooks()
{ {
UseActionHook = Service.GameInteropProvider.HookFromAddress<UseActionDelegate>((nint)ActionManager.MemberFunctionPointers.UseAction, UseActionDetour); UseActionHook = Service.GameInteropProvider.HookFromAddress<UseActionDelegate>((nint)ActionManager.MemberFunctionPointers.UseAction, UseActionDetour);
IsActionHighlightedHook = Service.GameInteropProvider.HookFromAddress<IsActionHighlightedDelegate>((nint)ActionManager.MemberFunctionPointers.IsActionHighlighted, IsActionHighlightedDetour);
UseActionHook.Enable(); UseActionHook.Enable();
IsActionHighlightedHook.Enable();
} }
private bool UseActionDetour(ActionManager* manager, CSActionType actionType, uint actionId, ulong targetId, uint param, uint useType, int pvp, nint a8) private bool UseActionDetour(ActionManager* manager, CSActionType actionType, uint actionId, ulong targetId, uint param, uint useType, int pvp, nint a8)
{ {
var canCast = manager->GetActionStatus(actionType, actionId) == 0; var canCast = manager->GetActionStatus(actionType, actionId) == 0;
var ret = UseActionHook.Original(manager, actionType, actionId, targetId, param, useType, pvp, a8); var ret = UseActionHook.Original(manager, actionType, actionId, targetId, param, useType, pvp, a8);
if (canCast && ret && (actionType == CSActionType.CraftAction || actionType == CSActionType.Action)) if (canCast && ret && actionType is CSActionType.CraftAction or CSActionType.Action)
{ {
var classJob = ClassJobUtils.GetClassJobFromIdx((byte)(Service.ClientState.LocalPlayer?.ClassJob.Id ?? 0)); var classJob = ClassJobUtils.GetClassJobFromIdx((byte)(Service.ClientState.LocalPlayer?.ClassJob.Id ?? 0));
if (classJob != null) if (classJob != null)
@@ -41,8 +48,40 @@ public sealed unsafe class Hooks : IDisposable
return ret; return ret;
} }
private byte IsActionHighlightedDetour(ActionManager* manager, CSActionType actionType, uint actionId)
{
var ret = IsActionHighlightedHook.Original(manager, actionType, actionId);
if (!Service.Configuration.SynthHelperAbilityAnts)
return ret;
if (!Service.Plugin.SynthHelperWindow.ShouldDrawAnts)
return ret;
if (actionType is not (CSActionType.CraftAction or CSActionType.Action))
return ret;
var jobId = Service.ClientState.LocalPlayer?.ClassJob.Id;
if (jobId == null)
return ret;
var classJob = ClassJobUtils.GetClassJobFromIdx((byte)jobId.Value);
if (classJob == null)
return ret;
var simActionType = ActionUtils.GetActionTypeFromId(actionId, classJob.Value, actionType == CSActionType.CraftAction);
if (simActionType == null)
return ret;
if (Service.Plugin.SynthHelperWindow.NextAction != simActionType)
return 0;
return 1;
}
public void Dispose() public void Dispose()
{ {
UseActionHook.Dispose(); UseActionHook.Dispose();
IsActionHighlightedHook.Dispose();
} }
} }
+10
View File
@@ -885,6 +885,16 @@ public sealed class Settings : Window, IDisposable
ref isDirty ref isDirty
); );
DrawOption(
"Draw Ability Ants",
"Turns your hotbar into a whack-a-mole game! Draws ants for " +
"the next action that should be executed. Also disables ants " +
"for things like combo actions and condition procs.",
Config.SynthHelperAbilityAnts,
v => Config.SynthHelperAbilityAnts = v,
ref isDirty
);
DrawOption( DrawOption(
"Step Count", "Step Count",
"The minimum number of future steps to solve for during an in-game craft.", "The minimum number of future steps to solve for during an in-game craft.",
+35 -22
View File
@@ -46,6 +46,8 @@ public sealed unsafe class SynthHelper : Window, IDisposable
public RecipeData? RecipeData { get; private set; } public RecipeData? RecipeData { get; private set; }
public CharacterStats? CharacterStats { get; private set; } public CharacterStats? CharacterStats { get; private set; }
public SimulationInput? SimulationInput { get; private set; } public SimulationInput? SimulationInput { get; private set; }
public ActionType? NextAction => (ShouldOpen && Macro.Count > 0) ? Macro[0].Action : null;
public bool ShouldDrawAnts => ShouldOpen;
public bool IsCrafting { get; private set; } public bool IsCrafting { get; private set; }
private int CurrentActionCount { get; set; } private int CurrentActionCount { get; set; }
@@ -65,8 +67,6 @@ public sealed unsafe class SynthHelper : Window, IDisposable
private SimulationState currentState; private SimulationState currentState;
private SimulatedMacro Macro { get; } = new(); private SimulatedMacro Macro { get; } = new();
private bool IsSuggestedActionExecutionQueued { get; set; }
private CancellationTokenSource? HelperTaskTokenSource { get; set; } private CancellationTokenSource? HelperTaskTokenSource { get; set; }
private Exception? HelperTaskException { get; set; } private Exception? HelperTaskException { get; set; }
private Solver.Solver? HelperTaskObject { get; set; } private Solver.Solver? HelperTaskObject { get; set; }
@@ -133,9 +133,6 @@ public sealed unsafe class SynthHelper : Window, IDisposable
} }
} }
if (!ShouldCalculate)
IsSuggestedActionExecutionQueued = false;
if (!ShouldOpen) if (!ShouldOpen)
{ {
StyleAlpha = LastAlpha = null; StyleAlpha = LastAlpha = null;
@@ -159,10 +156,24 @@ public sealed unsafe class SynthHelper : Window, IDisposable
if (!Service.Configuration.EnableSynthHelper) if (!Service.Configuration.EnableSynthHelper)
return false; return false;
if (Service.Configuration.DisableSynthHelperOnMacro && if (Service.Configuration.DisableSynthHelperOnMacro)
RaptureShellModule.Instance()->MacroCurrentLine >= 0 && {
!IsSuggestedActionExecutionQueued) var module = RaptureShellModule.Instance();
return false; if (module->MacroCurrentLine >= 0)
{
var hasCraftAction = false;
foreach (ref var line in module->MacroLines)
{
if (line.EqualToString("/craftaction"))
{
hasCraftAction = true;
break;
}
}
if (!hasCraftAction)
return false;
}
}
Addon = (AddonSynthesis*)Service.GameGui.GetAddonByName("Synthesis"); Addon = (AddonSynthesis*)Service.GameGui.GetAddonByName("Synthesis");
@@ -239,8 +250,6 @@ public sealed unsafe class SynthHelper : Window, IDisposable
ImGui.PopStyleVar(); ImGui.PopStyleVar();
base.PostDraw(); base.PostDraw();
IsSuggestedActionExecutionQueued = false;
} }
public override void Draw() public override void Draw()
@@ -311,19 +320,16 @@ public sealed unsafe class SynthHelper : Window, IDisposable
isPressed = ImGuiExtras.ButtonBehavior(bb, id, out isHovered, out isHeld, ImGuiButtonFlags.None); 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).ImGuiHandle, new(imageSize), default, Vector2.One, 0, default, failedAction ? new(1, 1, 1, ImGui.GetStyle().DisabledAlpha) : Vector4.One);
if (isPressed || IsSuggestedActionExecutionQueued) if (isPressed && i == 0)
{ {
if (canExecute && i == 0) if (ExecuteNextAction())
{
Service.Chat.SendMessage($"/ac \"{action.GetName(RecipeData.ClassJob)}\"");
break; break;
}
} }
if (isHovered) if (isHovered)
{ {
ImGuiUtils.Tooltip($"{action.GetName(RecipeData!.ClassJob)}\n" + ImGuiUtils.Tooltip($"{action.GetName(RecipeData!.ClassJob)}\n" +
$"{actionBase.GetTooltip(CreateSim(lastState), true)}" + $"{actionBase.GetTooltip(CreateSim(lastState), true)}" +
$"{(canExecute && i == 0 ? "Click or run /craftaction to Execute" : string.Empty)}"); $"{(canExecute && i == 0 ? "Click or run /craftaction to execute" : string.Empty)}");
hoveredState = state; hoveredState = state;
} }
lastState = state; lastState = state;
@@ -475,6 +481,18 @@ public sealed unsafe class SynthHelper : Window, IDisposable
Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), [], null); Service.Plugin.OpenMacroEditor(CharacterStats!, RecipeData!, new(Service.ClientState.LocalPlayer!.StatusList), [], null);
} }
public bool ExecuteNextAction()
{
var canExecute = !Service.Condition[ConditionFlag.Crafting40];
var action = NextAction;
if (canExecute && action != null)
{
Service.Chat.SendMessage($"/ac \"{action.Value.GetName(RecipeData!.ClassJob)}\"");
return true;
}
return false;
}
private void OnStartCrafting(ushort recipeId) private void OnStartCrafting(ushort recipeId)
{ {
var shouldUpdateInput = false; var shouldUpdateInput = false;
@@ -652,11 +670,6 @@ public sealed unsafe class SynthHelper : Window, IDisposable
HelperTaskTokenSource?.Cancel(); HelperTaskTokenSource?.Cancel();
} }
public void QueueSuggestedActionExecution()
{
IsSuggestedActionExecutionQueued = true;
}
private static Sim CreateSim(in SimulationState state) => private static Sim CreateSim(in SimulationState state) =>
Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state }; Service.Configuration.ConditionRandomness ? new Sim() { State = state } : new SimNoRandom() { State = state };