Skip to content

Commit

Permalink
Merge branch 'mergeWIP2'
Browse files Browse the repository at this point in the history
  • Loading branch information
CarnifexOptimus committed Jul 19, 2024
2 parents 4e0d703 + 9e71950 commit e287a5a
Show file tree
Hide file tree
Showing 92 changed files with 548 additions and 509 deletions.
2 changes: 1 addition & 1 deletion BossMod/AI/AIBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ private NavigationDecision BuildNavigationDecision(Actor player, Actor master, r
if (_config.ForbidMovement)
return new() { LeewaySeconds = float.MaxValue };
if (_followMaster && !_config.FollowTarget || _followMaster && _config.FollowTarget && target == null)
return NavigationDecision.Build(_naviCtx, WorldState, autorot.Hints, player, master.Position, 1, new(), Positional.Any);
return NavigationDecision.Build(_naviCtx, WorldState, autorot.Hints, player, master.Position, _config.MaxDistanceToTarget, new(), Positional.Any);
if (_followMaster && _config.FollowTarget && target != null)
return NavigationDecision.Build(_naviCtx, WorldState, autorot.Hints, player, target.Position, target.HitboxRadius + (_config.DesiredPositional != Positional.Any ? 2.6f : _config.MaxDistanceToTarget), target.Rotation, _config.DesiredPositional);
if (targeting.Target == null)
Expand Down
4 changes: 2 additions & 2 deletions BossMod/AI/AIConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ sealed class AIConfig : ConfigNode
[PropertyCombo(["Any", "Flank", "Rear", "Front"])]
public Positional DesiredPositional = Positional.Any;

[PropertyDisplay("Max distance to target for positional any")]
public float MaxDistanceToTarget = 25;
[PropertyDisplay("Max distance to target/slot")]
public float MaxDistanceToTarget = 2.6f;
}
4 changes: 1 addition & 3 deletions BossMod/AI/AIManagementWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public override void Draw()
_config.Modified.Fire();
}
ImGui.SameLine();
ImGui.Text("Max distance to target");
ImGui.Text("Max distance to target/slot");
ImGui.SameLine();
ImGui.SetNextItemWidth(100);
var maxDistanceStr = _config.MaxDistanceToTarget.ToString(CultureInfo.InvariantCulture);
Expand All @@ -91,8 +91,6 @@ public override void Draw()
_config.Modified.Fire();
}
}
ImGui.SameLine();
ImGui.Text("for positional = any");
ImGui.Text("Autorotation AI preset");
ImGui.SameLine();
ImGui.SetNextItemWidth(250);
Expand Down
16 changes: 7 additions & 9 deletions BossMod/ActionQueue/ActionQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
// - repeat the process until no more actions can be found
public sealed class ActionQueue
{
public readonly record struct Entry(ActionID Action, Actor? Target, float Priority, Vector3 TargetPos = default, Angle? FacingAngle = null);
public readonly record struct Entry(ActionID Action, Actor? Target, float Priority, float Expire = float.MaxValue, float Delay = 0, Vector3 TargetPos = default, Angle? FacingAngle = null);

// reference priority guidelines
// values divisible by 1000 are reserved for standard cooldown planner priorities; to disambiguate, small value < 1 could be added to the actions whose window ends earlier
// code should avoid adding several actions with identical priority for consistence; consider using values like 1100 or 1230 (not divisible by 1000, but divisible by 10) to allow user to fine-tune custom priorities
// values divisible by 1000 are reserved for standard cooldown planner priorities
// for actions with identical priorities, the 'expiration' field is used to disambiguate (entries expiring earlier are higher effective priority)
// code should avoid adding several actions with identical priority for consistency; consider using values like 1100 or 1230 (not divisible by 1000, but divisible by 10) to allow user to fine-tune custom priorities
// note that actions with priority < 0 will never be executed; they can still be added to the queue if it's convenient for the implementation
public static class Priority
{
Expand All @@ -32,19 +33,16 @@ public static class Priority
public const float ManualOGCD = 4001; // manually pressed ogcd should be higher priority than any non-gcd, but lower than any gcd
public const float ManualGCD = 4999; // manually pressed gcd should be higher priority than any gcd; it's still lower priority than VeryHigh, since presumably that action is planned to delay gcd
public const float ManualEmergency = 9000; // this action should be used asap, because user is spamming it

// small delta to use for disambiguating actions with identical priority
public const float Delta = 0.01f;
}

public readonly List<Entry> Entries = [];

public void Clear() => Entries.Clear();
public void Push(ActionID action, Actor? target, float priority, Vector3 targetPos = default, Angle? facingAngle = null) => Entries.Add(new(action, target, priority, targetPos, facingAngle));
public void Push(ActionID action, Actor? target, float priority, float expire = float.MaxValue, float delay = 0, Vector3 targetPos = default, Angle? facingAngle = null) => Entries.Add(new(action, target, priority, expire, delay, targetPos, facingAngle));

public Entry FindBest(WorldState ws, Actor player, ReadOnlySpan<Cooldown> cooldowns, float animationLock, AIHints hints, float instantAnimLockDelay)
{
Entries.SortByReverse(e => e.Priority);
Entries.SortByReverse(e => (e.Priority, -e.Expire));
Entry best = default;
float deadline = float.MaxValue; // any candidate we consider, if executed, should allow executing next action by this deadline
foreach (ref var candidate in Entries.AsSpan())
Expand All @@ -56,7 +54,7 @@ public Entry FindBest(WorldState ws, Actor player, ReadOnlySpan<Cooldown> cooldo
if (def == null || !def.AllowedClasses[(int)player.Class] || player.Level < def.MinLevel || !(ActionDefinitions.Instance.UnlockCheck?.Invoke(def.UnlockLink) ?? true))
continue; // unregistered or locked action

var startDelay = Math.Max(Math.Max(0, animationLock), def.ReadyIn(cooldowns));
var startDelay = Math.Max(Math.Max(candidate.Delay, animationLock), def.ReadyIn(cooldowns));

// TODO: adjusted cast time!
var duration = def.CastTime > 0 ? def.CastTime + def.CastAnimLock : def.InstantAnimLock + instantAnimLockDelay;
Expand Down
6 changes: 3 additions & 3 deletions BossMod/ActionTweaks/ManualActionQueueTweak.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ public void FillQueue(ActionQueue queue)
if (_emergencyMode)
{
ref var entry = ref _queue.Ref(0);
queue.Push(entry.Action, entry.Target, ActionQueue.Priority.ManualEmergency, entry.TargetPos, entry.FacingAngle);
queue.Push(entry.Action, entry.Target, ActionQueue.Priority.ManualEmergency, 0, 0, entry.TargetPos, entry.FacingAngle);
}
else
{
var prioDelta = _queue.Count;
float expireOrder = 0; // we don't actually care about values, only ordering...
foreach (ref var e in _queue.AsSpan())
queue.Push(e.Action, e.Target, (e.Definition.IsGCD ? ActionQueue.Priority.ManualGCD : ActionQueue.Priority.ManualOGCD) + --prioDelta * ActionQueue.Priority.Delta, e.TargetPos, e.FacingAngle);
queue.Push(e.Action, e.Target, e.Definition.IsGCD ? ActionQueue.Priority.ManualGCD : ActionQueue.Priority.ManualOGCD, expireOrder++, 0, e.TargetPos, e.FacingAngle);
}
}

Expand Down
8 changes: 4 additions & 4 deletions BossMod/Autorotation/Legacy/CommonState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ public int FindDutyActionSlot(ActionID action, ActionID other)
public bool CanWeave(float cooldown, float actionLock, float deadline) => deadline < 10000 ? MathF.Max(cooldown, AnimationLock) + actionLock + AnimationLockDelay <= deadline : cooldown <= AnimationLock;
public bool CanWeave<AID>(AID aid, float actionLock, float deadline) where AID : Enum => CanWeave(CD(aid), actionLock, deadline);

public void UpdateCommon(Actor? target)
public void UpdateCommon(Actor? target, float estimatedAnimLockDelay)
{
var vuln = Module.Manager.Planner?.EstimateTimeToNextVulnerable() ?? (false, 10000);
var downtime = Module.Manager.Planner?.EstimateTimeToNextDowntime() ?? (false, 0);
var poslock = Module.Manager.Planner?.EstimateTimeToNextPositioning() ?? (false, 10000);

TargetingEnemy = target != null && target.Type is ActorType.Enemy or ActorType.Part && !target.IsAlly;
RangeToTarget = target != null ? (target.Position - Module.Player.Position).Length() - target.HitboxRadius - Module.Player.HitboxRadius : float.MaxValue;
AnimationLock = Module.Manager.ActionManager.EffectiveAnimationLock;
AnimationLockDelay = Module.Manager.ActionManager.AnimationLockDelayEstimate;
RangeToTarget = Module.Player.DistanceToHitbox(target);
AnimationLock = (Module.Player.CastInfo?.RemainingTime ?? 0) + Module.World.Client.AnimationLock;
AnimationLockDelay = estimatedAnimLockDelay;

RaidBuffsLeft = vuln.Item1 ? vuln.Item2 : 0;
foreach (var status in Module.Player.Statuses.Where(s => IsDamageBuff(s.ID)))
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyBRD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ public LegacyBRD(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
if (_state.AnimationLockDelay < 0.1f)
_state.AnimationLockDelay = 0.1f; // TODO: reconsider; we generally don't want triple weaves or extra-late proc weaves

Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyDNC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ public LegacyDNC(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.AnimationLockDelay = MathF.Max(0.1f, _state.AnimationLockDelay);

var gauge = GetGauge<DancerGauge>();
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyDRG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ public LegacyDRG(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);

var gauge = GetGauge<DragoonGauge>();
_state.FirstmindFocusCount = gauge.FirstmindsFocusCount;
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyGNB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ public LegacyGNB(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HaveTankStance = Player.FindStatus(GNB.SID.RoyalGuard) != null;
//if (_state.ComboLastMove == GNB.AID.SolidBarrel)
// _state.ComboTimeLeft = 0;
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyMNK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ public LegacyMNK(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);

var gauge = GetGauge<MonkGauge>();
_state.Chakra = gauge.Chakra;
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyRPR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ public LegacyRPR(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HasSoulsow = Player.FindStatus(RPR.SID.Soulsow) != null;

var gauge = GetGauge<ReaperGauge>();
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacySAM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ public LegacySAM(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);

var newTsubameCooldown = _state.CD(SAM.AID.TsubameGaeshi);
if (newTsubameCooldown > _tsubameCooldown + 10) // eliminate variance, cd increment is 60s
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Legacy/LegacyWAR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ public LegacyWAR(RotationModuleManager manager, Actor player) : base(manager, pl
_state = new(this);
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
_state.UpdateCommon(primaryTarget);
_state.UpdateCommon(primaryTarget, estimatedAnimLockDelay);
_state.HaveTankStance = Player.FindStatus(WAR.SID.Defiance) != null;

_state.Gauge = GetGauge<WarriorGauge>().BeastGauge;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/PlanExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public StrategyValues ActiveStrategyOverrides(Type module)
{
var entry = GetEntryAt(data[i], t, s);
if (entry != null)
res.Values[i] = entry.Value;
res.Values[i] = entry.Value with { ExpireIn = entry.WindowEnd - t };
}
return res;
}
Expand Down
7 changes: 5 additions & 2 deletions BossMod/Autorotation/RotationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public abstract class RotationModule(RotationModuleManager manager, Actor player
public AIHints Hints => Manager.Hints;

// the main entry point of the module - given a set of strategy values, fill the queue with a set of actions to execute
public abstract void Execute(StrategyValues strategy, Actor? primaryTarget);
public abstract void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay);

public virtual string DescribeState() => "";

Expand All @@ -112,10 +112,13 @@ public bool TraitUnlocked(uint id)
// expected usage is `ResolveTargetOverride(strategy) ?? CustomSmartTargetingLogic(...)`
protected Actor? ResolveTargetOverride(in StrategyValue strategy) => Manager.ResolveTargetOverride(strategy);

// TODO: reconsider...
protected unsafe T GetGauge<T>() where T : unmanaged
{
T res = default;
((ulong*)&res)[1] = World.Client.GaugePayload;
((ulong*)&res)[1] = World.Client.GaugePayload.Low;
if (sizeof(T) > 16)
((ulong*)&res)[2] = World.Client.GaugePayload.High;
return res;
}
}
4 changes: 2 additions & 2 deletions BossMod/Autorotation/RotationModuleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void Dispose()
_subscriptions.Dispose();
}

public void Update()
public void Update(float estimatedAnimLockDelay)
{
// see whether current plan matches what should be active, and update if not; only rebuild actions if there is no active override
var expectedPlan = CalculateExpectedPlan();
Expand All @@ -87,7 +87,7 @@ public void Update()
{
var mt = m.Module.GetType();
var values = Preset?.ActiveStrategyOverrides(mt) ?? Planner?.ActiveStrategyOverrides(mt) ?? throw new InvalidOperationException("Both preset and plan are null, but there are active modules");
m.Module.Execute(values, target);
m.Module.Execute(values, target, estimatedAnimLockDelay);
}
}

Expand Down
1 change: 1 addition & 0 deletions BossMod/Autorotation/Strategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public record struct StrategyValue()
public StrategyTarget Target; // target selection strategy
public int TargetParam; // strategy-specific parameter
public string Comment = ""; // user-editable comment string
public float ExpireIn = float.MaxValue; // time until strategy expires
}

public readonly record struct StrategyValues(List<StrategyConfig> Configs)
Expand Down
9 changes: 9 additions & 0 deletions BossMod/Autorotation/UIPlanEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public override void Draw()
if (UIMisc.Button("Save", !_planner.Modified, "No changes"))
Save();
ImGui.SameLine();
if (UIMisc.Button("Delete", !ImGui.GetIO().KeyShift, "Hold shift to delete"))
Delete();
ImGui.SameLine();
_planner.DrawCommonControls();

_selectedPhase = _planner.DrawPhaseControls(_selectedPhase);
Expand All @@ -47,4 +50,10 @@ private void Save()
_original = newPlan;
_planner.Modified = false;
}

private void Delete()
{
_db.ModifyPlan(_original, null);
IsOpen = false;
}
}
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassBRDUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3);
ExecuteSimple(strategy.Option(Track.WardensPaean), BRD.AID.WardensPaean, Player);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassDNCUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3);
ExecuteSimple(strategy.Option(Track.CuringWaltz), DNC.AID.CuringWaltz, Player);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassDRGUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3);
}
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Autorotation/Utility/ClassGNBUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3, IDStanceApply, IDStanceRemove, (uint)GNB.SID.RoyalGuard);
ExecuteSimple(strategy.Option(Track.Camouflage), GNB.AID.Camouflage, Player);
Expand All @@ -46,6 +46,6 @@ public override void Execute(StrategyValues strategy, Actor? primaryTarget)
_ => default
};
if (aid != default)
Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), ResolveTargetOverride(hoc.Value) ?? CoTank() ?? Player, hoc.Priority());
Hints.ActionsToExecute.Push(ActionID.MakeSpell(aid), ResolveTargetOverride(hoc.Value) ?? CoTank() ?? Player, hoc.Priority(), hoc.Value.ExpireIn);
}
}
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassMNKUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3);
ExecuteSimple(strategy.Option(Track.Mantra), MNK.AID.Mantra, Player);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassPLDUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3, IDStanceApply, IDStanceRemove, (uint)PLD.SID.IronWill);
ExecuteSimple(strategy.Option(Track.Sheltron), PLD.AID.Sheltron, Player);
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Autorotation/Utility/ClassRPRUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static RotationModuleDefinition Definition()
return res;
}

public override void Execute(StrategyValues strategy, Actor? primaryTarget)
public override void Execute(StrategyValues strategy, Actor? primaryTarget, float estimatedAnimLockDelay)
{
ExecuteShared(strategy, IDLimitBreak3);
ExecuteSimple(strategy.Option(Track.ArcaneCrest), RPR.AID.ArcaneCrest, Player);
Expand Down
Loading

0 comments on commit e287a5a

Please sign in to comment.