Files
BardFrontline/Core/RequestGate.cs
T

45 lines
2.2 KiB
C#

namespace BardFrontline.Core;
// One outstanding native request. Cooldown changes alone are insufficient for a cleanse: wait for acknowledgement.
public sealed class RequestGate
{
public ActionDecision? Pending { get; private set; }
private double sentAt;
private ushort beforeSequence;
private bool sequenceObserved;
private ushort requestSequence;
private readonly Dictionary<(Skill, ulong), double> failures = [];
public string Reason { get; private set; } = "";
public void Submitted(ActionDecision decision, double now, ushort before, ushort after)
{
Pending = decision; sentAt = now; beforeSequence = before;
sequenceObserved = after != before; requestSequence = after; Reason = "等待动作确认";
}
public bool Update(double now, ushort used, ushort handled, bool guardActive, bool cleansingStateChanged, bool ownedCastInProgress = false)
{
if (Pending == null) return false;
if (!sequenceObserved && used != beforeSequence) { sequenceObserved = true; requestSequence = used; }
var acknowledged = sequenceObserved && unchecked((short)(handled - requestSequence)) >= 0;
var elapsed = now - sentAt;
var release = Pending.Skill switch
{
Skill.Guard => guardActive || acknowledged && elapsed >= .5,
Skill.Purify or Skill.WardensPaean => cleansingStateChanged || acknowledged && elapsed >= .5,
_ => acknowledged && elapsed >= .1,
};
if (release) { Pending = null; Reason = ""; return false; }
if (ownedCastInProgress) return true;
if (elapsed < 2) return true;
Fail(Pending, now, "动作确认超时,短暂退避"); Pending = null;
return false;
}
public bool IsBlocked(Skill s, ulong id, double now) => failures.TryGetValue((s, id), out var until) && until > now;
public void Fail(ActionDecision d, double now, string reason)
{
failures[(d.Skill, d.TargetId)] = now + .5; Reason = reason;
foreach (var key in failures.Where(x => x.Value <= now).Select(x => x.Key).ToArray()) failures.Remove(key);
}
public void Reset() { Pending = null; failures.Clear(); Reason = ""; }
}