Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Commit

Permalink
fix: add deadtime for rotation checking.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArchiDog1998 committed Aug 16, 2023
1 parent 7cb567e commit 05f1413
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 78 deletions.
15 changes: 13 additions & 2 deletions RotationSolver.Basic/Actions/BaseAction_Target.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public partial class BaseAction
/// </summary>
public byte AOECount { private get; init; } = 3;

/// <summary>
/// How many time does this ation need the target keep in live.
/// </summary>
public float TimeToDie { get; init; } = 0;

/// <summary>
/// Is this action's target dead?
/// </summary>
Expand Down Expand Up @@ -341,8 +346,10 @@ private bool TargetHostileManual(BattleChara b, bool mustUse, int aoeCount, out
{
if (!mustUse)
{
var time = DataCenter.GetDeadTime(b);

//No need to dot.
if (TargetStatus != null && !ObjectHelper.CanDot(b)) return false;
if (TargetStatus != null && !float.IsNaN(time) && time < TimeToDie) return false;

//Already has status.
if (!CheckStatus(b)) return false;
Expand Down Expand Up @@ -500,7 +507,11 @@ private IEnumerable<BattleChara> TargetFilterFuncEot(IEnumerable<BattleChara> ta
if (TargetStatus == null || !IsEot) return tars;

var dontHave = tars.Where(CheckStatus);
var canDot = dontHave.Where(ObjectHelper.CanDot);
var canDot = dontHave.Where(b =>
{
var time = DataCenter.GetDeadTime(b);
return float.IsNaN(time) || time >= TimeToDie;
});

if (mustUse)
{
Expand Down
9 changes: 3 additions & 6 deletions RotationSolver.Basic/Configuration/Configs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public enum PluginConfigBool : byte
[Default(true)] DrawMeleeOffset,

[Default(true)] ShowMoveTarget,
[Default(false)] ShowHealthRatio,
[Default(false)] ShowTargetDeadTime,
[Default(true)] ShowTarget,
[Default(true)] ChooseAttackMark,
[Default(false)] CanAttackMarkAOE,
Expand Down Expand Up @@ -388,9 +388,8 @@ public enum PluginConfigFloat : byte
[Default(0.6f, 0.5f, 0.7f)] CountDownAhead,

[Default(24f)] MoveTargetAngle,
[Default(1.85f, 0f, 10f)] HealthRatioBoss,
[Default(0.8f, 0f, 10f)] HealthRatioDying,
[Default(1.2f, 0f, 10f)] HealthRatHealthRatioDotioBoss,
[Default(60, 10f, 1800f)] DeadTimeBoss,
[Default(10, 0f, 60)] DeadTimeDying,

[Default(16f, 9.6f, 96f)] CooldownFontSize,

Expand All @@ -401,8 +400,6 @@ public enum PluginConfigFloat : byte
[Default(8f)] ControlProgressHeight,
[Default(1.2f, 0f, 30f)] DistanceForMoving,
[Default(0.2f, 0.01f, 0.5f)] MaxPing,

[Default(1.8f)] HealthRatioDot,
}

public enum PluginConfigVector4 : byte
Expand Down
42 changes: 41 additions & 1 deletion RotationSolver.Basic/DataCenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,54 @@
using ECommons.GameHelpers;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Fate;
using Lumina.Excel.GeneratedSheets;
using Action = Lumina.Excel.GeneratedSheets.Action;
using CharacterManager = FFXIVClientStructs.FFXIV.Client.Game.Character.CharacterManager;

namespace RotationSolver.Basic;

internal static class DataCenter
{
private static readonly TimeSpan CheckSpan = TimeSpan.FromSeconds(2.5);

/// <summary>
/// How many seconds will the target die.
/// </summary>
/// <param name="b"></param>
/// <param name="wholeTime">whole time to die.</param>
/// <returns></returns>
internal static float GetDeadTime(BattleChara b, bool wholeTime = false)
{
if (b == null) return float.NaN;
var objectId = b.ObjectId;

DateTime startTime = DateTime.MinValue;
float thatTimeRatio = 0;
foreach (var (time, hpRatios) in RecordedHP)
{
if(hpRatios.TryGetValue(objectId, out var ratio) && ratio != 1)
{
startTime = time;
thatTimeRatio = ratio;
break;
}
}

var timespan = DateTime.Now - startTime;
if(startTime == DateTime.MinValue || timespan < CheckSpan) return float.NaN;

var ratioNow = b.GetHealthRatio();

var ratioReduce = thatTimeRatio - ratioNow;
if (ratioReduce <= 0) return float.NaN;

return (float)timespan.TotalSeconds / ratioReduce * (wholeTime ? 1 : ratioNow);
}
/// <summary>
/// Only recorded 15s hps.
/// </summary>
public const int HP_RECORD_TIME = 150;
internal static Queue<(DateTime time, SortedList<uint, float> hpRatios)> RecordedHP { get; } = new(HP_RECORD_TIME + 1);

internal static bool NoPoslock => Svc.Condition[ConditionFlag.OccupiedInEvent]
|| !Service.Config.GetValue(Configuration.PluginConfigBool.PoslockCasting)
//Key cancel.
Expand Down
72 changes: 30 additions & 42 deletions RotationSolver.Basic/Helpers/ObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ internal static bool CanInterrupt(this BattleChara b)
public static bool IsBoss(this BattleChara obj)
{
if (obj == null) return false;
if (obj.IsDummy() && !Service.Config.GetValue(Configuration.PluginConfigBool.ShowHealthRatio)) return true;
return obj.MaxHp >= GetHealthFromMulty(Service.Config.GetValue(Configuration.PluginConfigFloat.HealthRatioBoss))
if (obj.IsDummy() && !Service.Config.GetValue(Configuration.PluginConfigBool.ShowTargetDeadTime)) return true;
return DataCenter.GetDeadTime(obj, true) >= Service.Config.GetValue(Configuration.PluginConfigFloat.DeadTimeBoss)
|| !(obj.GetObjectNPC()?.IsTargetLine ?? true);
}

Expand All @@ -162,8 +162,8 @@ public static bool IsBoss(this BattleChara obj)
public static bool IsDying(this BattleChara b)
{
if (b == null) return false;
if (b.IsDummy() && !Service.Config.GetValue(Configuration.PluginConfigBool.ShowHealthRatio)) return false;
return b.CurrentHp <= GetHealthFromMulty(Service.Config.GetValue(Configuration.PluginConfigFloat.HealthRatioDying)) || b.GetHealthRatio() < 0.02f;
if (b.IsDummy() && !Service.Config.GetValue(Configuration.PluginConfigBool.ShowTargetDeadTime)) return false;
return DataCenter.GetDeadTime(b) <= Service.Config.GetValue(Configuration.PluginConfigFloat.DeadTimeDying) || b.GetHealthRatio() < 0.02f;
}

/// <summary>
Expand All @@ -174,22 +174,10 @@ public static bool IsDying(this BattleChara b)
public static float GetHealthRatio(this BattleChara b)
{
if (b == null) return 0;
if(DataCenter.RefinedHP.TryGetValue(b.ObjectId, out var hp)) return hp;
if (DataCenter.RefinedHP.TryGetValue(b.ObjectId, out var hp)) return hp;
return (float)b.CurrentHp / b.MaxHp;
}

/// <summary>
/// Can use dot on the target.
/// </summary>
/// <param name="b"></param>
/// <returns></returns>
public static bool CanDot(this BattleChara b)
{
if (b == null) return false;
if (b.IsDummy() && !Service.Config.GetValue(Configuration.PluginConfigBool.ShowHealthRatio)) return true;
return b.CurrentHp >= GetHealthFromMulty(Service.Config.GetValue(Configuration.PluginConfigFloat.HealthRatioDot));
}

internal static EnemyPositional FindEnemyPositional(this GameObject enemy)
{
Vector3 pPosition = enemy.Position;
Expand All @@ -206,31 +194,31 @@ internal static EnemyPositional FindEnemyPositional(this GameObject enemy)
return EnemyPositional.Flank;
}

internal static uint GetHealthFromMulty(float mult)
{
if (!Player.Available) return 0;

var role = Service.GetSheet<ClassJob>().GetRow(
Player.Object.ClassJob.Id).GetJobRole();
float multi = mult * role switch
{
JobRole.Tank => 1,
JobRole.Healer => 1.6f,
_ => 1.5f,
};

var partyCount = DataCenter.PartyMembers.Count();
if (partyCount > 4)
{
multi *= 6.4f;
}
else if (partyCount > 1)
{
multi *= 3.5f;
}

return (uint)(multi * Player.Object.MaxHp);
}
//internal static uint GetHealthFromMulty(float mult)
//{
// if (!Player.Available) return 0;

// var role = Service.GetSheet<ClassJob>().GetRow(
// Player.Object.ClassJob.Id).GetJobRole();
// float multi = mult * role switch
// {
// JobRole.Tank => 1,
// JobRole.Healer => 1.6f,
// _ => 1.5f,
// };

// var partyCount = DataCenter.PartyMembers.Count();
// if (partyCount > 4)
// {
// multi *= 6.4f;
// }
// else if (partyCount > 1)
// {
// multi *= 3.5f;
// }

// return (uint)(multi * Player.Object.MaxHp);
//}

/// <summary>
/// The distance from <paramref name="obj"/> to the player
Expand Down
9 changes: 4 additions & 5 deletions RotationSolver/Localization/ConfigTranslation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ internal static class ConfigTranslation
PluginConfigBool.TargetFatePriority => LocalizationManager.RightLang.ConfigWindow_Param_TargetFatePriority,
PluginConfigBool.TargetHuntingRelicLevePriority => LocalizationManager.RightLang.ConfigWindow_Param_TargetHuntingRelicLevePriority,
PluginConfigBool.TargetQuestPriority => LocalizationManager.RightLang.ConfigWindow_Param_TargetQuestPriority,
PluginConfigBool.ShowTargetDeadTime => LocalizationManager.RightLang.ConfigWindow_Param_ShowTargetDeadTime,


// extra
PluginConfigBool.SayOutStateChanged => LocalizationManager.RightLang.ConfigWindow_Param_SayOutStateChanged,
PluginConfigBool.PoslockCasting => LocalizationManager.RightLang.ConfigWindow_Param_PoslockCasting,
PluginConfigBool.ShowHealthRatio => LocalizationManager.RightLang.ConfigWindow_Param_ShowHealthRatio,
PluginConfigBool.ShowTooltips => LocalizationManager.RightLang.ConfigWindow_Param_ShowTooltips,
PluginConfigBool.InDebug => LocalizationManager.RightLang.ConfigWindow_Param_InDebug,
PluginConfigBool.AutoOpenChest => "Auto Open the treasure chest",
Expand Down Expand Up @@ -179,10 +179,9 @@ internal static class ConfigTranslation
PluginConfigFloat.HealthHealerRatio => LocalizationManager.RightLang.ConfigWindow_Param_HealthHealerRatio,
PluginConfigFloat.HealthTankRatio => LocalizationManager.RightLang.ConfigWindow_Param_HealthTankRatio,

// extra
PluginConfigFloat.HealthRatioBoss => LocalizationManager.RightLang.ConfigWindow_Param_HealthRatioBoss,
PluginConfigFloat.HealthRatioDying => LocalizationManager.RightLang.ConfigWindow_Param_HealthRatioDying,
PluginConfigFloat.HealthRatioDot => LocalizationManager.RightLang.ConfigWindow_Param_HealthRatioDot,
// target
PluginConfigFloat.DeadTimeBoss => LocalizationManager.RightLang.ConfigWindow_Param_DeadTimeBoss,
PluginConfigFloat.DeadTimeDying => LocalizationManager.RightLang.ConfigWindow_Param_DeadTimeDying,

_ => string.Empty,
};
Expand Down
7 changes: 3 additions & 4 deletions RotationSolver/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,11 @@ internal partial class Strings
public string ConfigWindow_Param_ShowTooltips { get; set; } = "Show tooltips";
public string ConfigWindow_Param_InDebug { get; set; } = "Debug Mode";

public string ConfigWindow_Param_ShowHealthRatio { get; set; } = "Show the health ratio for the check of Boss, Dying, Dot.";
public string ConfigWindow_Param_ShowTargetDeadTime { get; set; } = "Show the targets' dead time.";

public string ConfigWindow_Param_HealthRatioBoss { get; set; } = "If target's max health ratio is higher than this, regard it as Boss.";
public string ConfigWindow_Param_DeadTimeBoss { get; set; } = "If target's whole dead time is higher than this, regard it as Boss.";

public string ConfigWindow_Param_HealthRatioDying { get; set; } = "If target's current health ratio is lower than this, regard it is dying.";
public string ConfigWindow_Param_HealthRatioDot { get; set; } = "If target's current health ratio is higher than this, regard it can be dot.";
public string ConfigWindow_Param_DeadTimeDying { get; set; } = "If target's dead time is lower than this, regard it is dying.";
public string ConfigWindow_Param_PoslockModifier { get; set; } = "Set the modifier key to unlock the movement temporary";
public string ConfigWindow_Param_PoslockDescription { get; set; } = "LT is for gamepad player";
public string ConfigWindow_Param_TeachingMode { get; set; } = "Teaching mode";
Expand Down
6 changes: 2 additions & 4 deletions RotationSolver/UI/PainterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ public override void UpdateOnFrame(XIVPainter.XIVPainter painter)
((Drawing3DText)SubItems[i]).Text = string.Empty;
}

if (!Service.Config.GetValue(Basic.Configuration.PluginConfigBool.ShowHealthRatio)) return;

var calHealth = (double)ObjectHelper.GetHealthFromMulty(1);
if (!Service.Config.GetValue(PluginConfigBool.ShowTargetDeadTime)) return;

int index = 0;
foreach (GameObject t in DataCenter.AllTargets.OrderBy(ObjectHelper.DistanceToPlayer))
Expand All @@ -150,7 +148,7 @@ public override void UpdateOnFrame(XIVPainter.XIVPainter painter)

var item = (Drawing3DText)SubItems[index++];

item.Text = $"Health Ratio: {b.CurrentHp / calHealth:F2} / {b.MaxHp / calHealth:F2}";
item.Text = $"Health Ratio: {DataCenter.GetDeadTime(b):F2}s / {DataCenter.GetDeadTime(b, true):F2}s";
item.Color = HealthRatioColor;
item.Position = b.Position;

Expand Down
2 changes: 1 addition & 1 deletion RotationSolver/UI/RotationConfigWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ private static void DrawAbout()
ImGui.PopStyleColor();

var width = ImGui.GetWindowWidth();
if (IconSet.GetTexture("https://discordapp.com/api/guilds/1064448004498653245/embed.png?style=banner4", out var icon) && TextureButton(icon, width, width))
if (IconSet.GetTexture("https://discordapp.com/api/guilds/1064448004498653245/embed.png?style=banner2", out var icon) && TextureButton(icon, width, width))
{
Util.OpenLink("https://discord.gg/4fECHunam9");
}
Expand Down
15 changes: 5 additions & 10 deletions RotationSolver/UI/RotationConfigWindow_Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ private static void DrawUI()
new ColorEditSearchPlugin(PluginConfigVector4.HoveredBeneficialPositionColor)
),

new CheckBoxSearchPlugin(PluginConfigBool.ShowTargetDeadTime),

new CheckBoxSearchPlugin(PluginConfigBool.ShowTarget,
new DragFloatSearchPlugin(PluginConfigFloat.TargetIconSize, 0.002f),
new ColorEditSearchPlugin(PluginConfigVector4.TargetColor),
Expand Down Expand Up @@ -604,12 +606,13 @@ private static void DrawTargetConfig()
}),

new DragFloatRangeSearchPlugin(PluginConfigFloat.HostileDelayMin, PluginConfigFloat.HostileDelayMax, 0.002f),


};

private static readonly ISearchable[] _targetHostileSelectSearchable = new ISearchable[]
{
new DragFloatSearchPlugin(PluginConfigFloat.DeadTimeBoss, 0.02f),
new DragFloatSearchPlugin(PluginConfigFloat.DeadTimeDying, 0.02f),

new CheckBoxSearchPlugin(PluginConfigBool.OnlyAttackInView),
new CheckBoxSearchPlugin(PluginConfigBool.ChangeTargetForFate),
new CheckBoxSearchPlugin(PluginConfigBool.TargetFatePriority),
Expand Down Expand Up @@ -728,14 +731,6 @@ private static void DrawExtra()
Action = ActionID.Improvisation
}),

new CheckBoxSearchPlugin(PluginConfigBool.ShowHealthRatio, new ISearchable[]
{
new DragFloatSearchPlugin(PluginConfigFloat.HealthRatioBoss, 0.02f),
new DragFloatSearchPlugin(PluginConfigFloat.HealthRatioDying, 0.02f),
new DragFloatSearchPlugin(PluginConfigFloat.HealthRatioDot, 0.02f),

}),

new CheckBoxSearchPlugin(PluginConfigBool.UseStopCasting,new ISearchable[]
{
new DragFloatRangeSearchPlugin(PluginConfigFloat.StopCastingDelayMin, PluginConfigFloat.StopCastingDelayMin, 0.002f)
Expand Down
31 changes: 28 additions & 3 deletions RotationSolver/Updaters/TargetUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ internal unsafe static void UpdateTarget()
UpdateNamePlate(Svc.Objects.OfType<BattleChara>());
}

private static DateTime _lastUpdateDeadTime = DateTime.MinValue;
private static readonly TimeSpan _deadTimeSpan = TimeSpan.FromSeconds(0.1);
private static void UpdateDeadTime(IEnumerable<BattleChara> allTargets)
{
var now = DateTime.Now;
if (now - _lastUpdateDeadTime < _deadTimeSpan) return;

if(DataCenter.RecordedHP.Count >= DataCenter.HP_RECORD_TIME)
{
DataCenter.RecordedHP.Dequeue();
}

DataCenter.RecordedHP.Enqueue((now, new SortedList<uint, float>(allTargets.Where(b => b != null && b.CurrentHp != 0).ToDictionary(b => b.ObjectId, b => b.GetHealthRatio()))));
}

internal static void ClearTarget()
{
var empty = Array.Empty<BattleChara>();
Expand Down Expand Up @@ -68,7 +83,7 @@ private static float JobRange

private unsafe static void UpdateHostileTargets(IEnumerable<BattleChara> allTargets)
{
DataCenter.AllHostileTargets = allTargets.Where(b =>
allTargets = allTargets.Where(b =>
{
if (!b.IsNPCEnemy()) return false;

Expand All @@ -77,17 +92,27 @@ private unsafe static void UpdateHostileTargets(IEnumerable<BattleChara> allTarg

if (!b.IsTargetable()) return false;

return true;
});

UpdateDeadTime(allTargets);

DataCenter.AllHostileTargets = allTargets.Where(b =>
{
if (b.StatusList.Any(StatusHelper.IsInvincible)) return false;
return true;
});

DataCenter.HostileTargets.Delay(GetHostileTargets(DataCenter.AllHostileTargets.Where(b =>
{
if (Service.Config.GetValue(PluginConfigBool.OnlyAttackInView))
{
if (!Svc.GameGui.WorldToScreen(b.Position, out _)) return false;
}

return true;
});
})));

DataCenter.HostileTargets.Delay(GetHostileTargets(DataCenter.AllHostileTargets));
DataCenter.CanInterruptTargets.Delay(DataCenter.HostileTargets.Where(ObjectHelper.CanInterrupt));

DataCenter.TarOnMeTargets = DataCenter.HostileTargets.Where(tar => tar.TargetObjectId == Player.Object.ObjectId);
Expand Down

0 comments on commit 05f1413

Please sign in to comment.