Skip to content

Commit

Permalink
Merge pull request #417 from FFXIV-CombatReborn/targetting-update
Browse files Browse the repository at this point in the history
Refactor distance checks and enemy list handling
  • Loading branch information
LTS-FFXIV authored Sep 28, 2024
2 parents 863d0b0 + 0f39dce commit 52acb5a
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 55 deletions.
9 changes: 8 additions & 1 deletion Resources/HostileCastingArea.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,5 +640,12 @@
36610,
36612,
27145,
27181
27181,
24522,
13066,
13073,
13085,
13074,
26050,
26049
]
5 changes: 4 additions & 1 deletion Resources/HostileCastingTank.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@
33965,
35715,
37845,
29023
29023,
10542,
26040,
26041
]
8 changes: 0 additions & 8 deletions RotationSolver.Basic/Configuration/Configs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,6 @@ public const string
[UI("", Action = ActionID.ImprovisationPvE, Parent = nameof(PoslockCasting))]
public bool PosImprovisation { get; set; } = false;

[ConditionBool, UI("Add enemy list to the hostile targets.",
Filter = TargetConfig)]
private static readonly bool _addEnemyListToHostile = true;

[ConditionBool, UI("Only attack the targets in enemy list.",
Parent = nameof(AddEnemyListToHostile))]
private static readonly bool _onlyAttackInEnemyList = false;

[JobConfig, UI("Only used automatically if coded into the rotation", Filter = AutoActionUsage, PvPFilter = JobFilterType.NoJob)]
private readonly TinctureUseType _TinctureType = TinctureUseType.Nowhere;

Expand Down
12 changes: 12 additions & 0 deletions RotationSolver.Basic/Data/TargetHostileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,16 @@ public enum TargetHostileType : byte
/// </summary>
[Description("All targets when solo, or previously engaged.")]
AllTargetsWhenSolo,

/// <summary>
/// Targets in your enemy list.
/// </summary>
[Description("Only attack targets in your parties enemy list")]
TargetIsInEnemiesList,

/// <summary>
/// All targets when solo, or only attack targets in your parties enemy list.
/// </summary>
[Description("All targets when solo, or only attack targets in your parties enemy list")]
AllTargetsWhenSoloTargetIsInEnemiesList,
}
10 changes: 5 additions & 5 deletions RotationSolver.Basic/DataCenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,12 @@ public static ulong[] TreasureCharas

public static bool HasHostilesInRange => NumberOfHostilesInRange > 0;
public static bool HasHostilesInMaxRange => NumberOfHostilesInMaxRange > 0;
public static int NumberOfHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange);
public static int NumberOfHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= 25);
public static int NumberOfAllHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange);
public static int NumberOfAllHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() <= 25);
public static int NumberOfHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange);
public static int NumberOfHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < 25);
public static int NumberOfAllHostilesInRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange);
public static int NumberOfAllHostilesInMaxRange => AllHostileTargets.Count(o => o.DistanceToPlayer() < 25);

public static bool MobsTime => AllHostileTargets.Count(o => o.DistanceToPlayer() <= JobRange && o.CanSee())
public static bool MobsTime => AllHostileTargets.Count(o => o.DistanceToPlayer() < JobRange && o.CanSee())
>= Service.Config.AutoDefenseNumber;

public static bool AreHostilesCastingKnockback => AllHostileTargets.Any(IsHostileCastingKnockback);
Expand Down
117 changes: 95 additions & 22 deletions RotationSolver.Basic/Helpers/ObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision;
using FFXIVClientStructs.FFXIV.Component.GUI;
using RotationSolver.Basic.Configuration;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace RotationSolver.Basic.Helpers;
Expand Down Expand Up @@ -95,53 +98,123 @@ internal static bool IsAttackable(this IBattleChara battleChara)
if (tarFateId != 0 && tarFateId != DataCenter.FateId) return false;
}

if (Service.Config.AddEnemyListToHostile)
{
if (battleChara.IsInEnemiesList()) return true;
// Only attack
if (Service.Config.OnlyAttackInEnemyList) return false;
}

// Tar on me
if (battleChara.TargetObject == Player.Object
|| battleChara.TargetObject?.OwnerId == Player.Object.GameObjectId) return true;

if (battleChara.IsOthersPlayers()) return false;

if (battleChara.IsTopPriorityHostile()) return true;

if (Service.CountDownTime > 0 || DataCenter.IsPvP) return true;

return DataCenter.RightNowTargetToHostileType switch {
// Tar on me
if (battleChara.TargetObject == Player.Object
|| battleChara.TargetObject?.OwnerId == Player.Object.GameObjectId) return true;

return DataCenter.RightNowTargetToHostileType switch
{
TargetHostileType.AllTargetsCanAttack => true,
TargetHostileType.TargetsHaveTarget => battleChara.TargetObject is IBattleChara,
TargetHostileType.AllTargetsWhenSolo => DataCenter.PartyMembers.Length < 2 || battleChara.TargetObject is IBattleChara,
TargetHostileType.AllTargetsWhenSoloInDuty => (DataCenter.PartyMembers.Length < 2 && Svc.Condition[ConditionFlag.BoundByDuty])
|| battleChara.TargetObject is IBattleChara,
TargetHostileType.TargetIsInEnemiesList => battleChara.TargetObject is IBattleChara target && target.IsInEnemiesList(),
TargetHostileType.AllTargetsWhenSoloTargetIsInEnemiesList => DataCenter.PartyMembers.Length < 2 || battleChara.TargetObject is IBattleChara target && target.IsInEnemiesList(),
_ => true,
};
}

internal static unsafe bool IsInEnemiesList(this IBattleChara IBattleChara)
private static string RemoveControlCharacters(string input)
{
if (string.IsNullOrEmpty(input))
return input;

// Use a StringBuilder for efficient string manipulation
var output = new StringBuilder(input.Length);
foreach (char c in input)
{
// Exclude control characters and private use area characters
if (!char.IsControl(c) && (c < '\uE000' || c > '\uF8FF'))
{
output.Append(c);
}
}
return output.ToString();
}

//Below never returns true
internal static unsafe bool IsInEnemiesList(this IBattleChara battleChara)
{
var addons = Service.GetAddons<AddonEnemyList>();

if (!addons.Any()) return false;
if (!addons.Any())
{
return false;
}

if (!addons.Any())
{
return false;
}

var addon = addons.FirstOrDefault();
var enemy = (AddonEnemyList*)addon;
if (addon == IntPtr.Zero)
{
return false;
}

var numArray = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance()->GetUIModule()->GetRaptureAtkModule()->AtkModule.AtkArrayDataHolder.NumberArrays[19];
if (numArray == null) return false;
var enemyList = (AddonEnemyList*)addon;

const int baseIndex = 8;
const int step = 6;
// Ensure that EnemyOneComponent is valid
if (enemyList->EnemyOneComponent == null)
{
return false;
}

// EnemyCount indicates how many enemies are in the list
var enemyCount = enemyList->EnemyCount;

for (var i = 0; i < enemy->EnemyCount; i++)
for (int i = 0; i < enemyCount; i++)
{
var id = (uint)numArray->IntArray[baseIndex + i * step];
// Access each enemy component
var enemyComponentPtr = enemyList->EnemyOneComponent + i;
if (enemyComponentPtr == null || *enemyComponentPtr == null)
{
continue;
}

var enemyComponent = *enemyComponentPtr;
var atkComponentBase = enemyComponent->AtkComponentBase;

if (IBattleChara.GameObjectId == id) return true;
// Access the UldManager's NodeList
var uldManager = atkComponentBase.UldManager;

for (int j = 0; j < uldManager.NodeListCount; j++)
{
var node = uldManager.NodeList[j];
if (node == null)
continue;

if (node->Type == NodeType.Text)
{
var textNode = (AtkTextNode*)node;
if (textNode->NodeText.StringPtr == null)
continue;

// Read the enemy's name
var enemyNameRaw = Marshal.PtrToStringUTF8((IntPtr)textNode->NodeText.StringPtr);
if (string.IsNullOrEmpty(enemyNameRaw))
continue;

// Remove control characters from the enemy's name
var enemyName = RemoveControlCharacters(enemyNameRaw);

// Compare with battleChara's name
if (string.Equals(enemyName, battleChara.Name.TextValue, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
}

return false;
}

Expand Down
4 changes: 1 addition & 3 deletions RotationSolver/RotationSolverPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
using RotationSolver.Commands;
using RotationSolver.Data;
using RotationSolver.Helpers;

using RotationSolver.UI;
using RotationSolver.UI.HighlightTeachingMode;
using RotationSolver.UI.HighlightTeachingMode.ElementSpecial;
using RotationSolver.Updaters;
using static FFXIVClientStructs.FFXIV.Client.UI.Agent.AgentPartyMember.Delegates;
using WelcomeWindow = RotationSolver.UI.WelcomeWindow;

namespace RotationSolver;
Expand Down Expand Up @@ -249,7 +247,7 @@ internal static void UpdateDisplayWindow()

isValid &= !Service.Config.OnlyShowWithHostileOrInDuty
|| Svc.Condition[ConditionFlag.BoundByDuty]
|| DataCenter.AllHostileTargets.Any(o => o.DistanceToPlayer() <= 25);
|| DataCenter.AllHostileTargets.Any(o => o.DistanceToPlayer() < 25);

_controlWindow!.IsOpen = isValid && Service.Config.ShowControlWindow;
_cooldownWindow!.IsOpen = isValid && Service.Config.ShowCooldownWindow;
Expand Down
30 changes: 15 additions & 15 deletions RotationSolver/UI/RotationConfigWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2607,21 +2607,21 @@ private static void DrawDebug()
}

private static readonly CollapsingHeaderGroup _debugHeader = new(new()
{
{() => DataCenter.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus},
{() => "Status", DrawStatus },
{() => "Party", DrawParty },
{() => "Target Data", DrawTargetData },
{() => "Next Action", DrawNextAction },
{() => "Last Action", DrawLastAction },
{() => "Others", DrawOthers },
{() => "Effect", () =>
{
ImGui.Text(Watcher.ShowStrSelf);
ImGui.Separator();
ImGui.Text(DataCenter.Role.ToString());
} },
});
{
{() => DataCenter.RightNowRotation != null ? "Rotation" : string.Empty, DrawDebugRotationStatus},
{() => "Status", DrawStatus },
{() => "Party", DrawParty },
{() => "Target Data", DrawTargetData },
{() => "Next Action", DrawNextAction },
{() => "Last Action", DrawLastAction },
{() => "Others", DrawOthers },
{() => "Effect", () =>
{
ImGui.Text(Watcher.ShowStrSelf);
ImGui.Separator();
ImGui.Text(DataCenter.Role.ToString());
} },
});

private static void DrawDebugRotationStatus()
{
Expand Down

0 comments on commit 52acb5a

Please sign in to comment.