acdream/src/AcDream.Core.Net/Transport/TransportStats.cs
Erik f7aa8e0eb7
All checks were successful
CI / linux-portable (push) Successful in 3m41s
CI / windows-gate (push) Successful in 6m49s
CI / release (push) Successful in 3m22s
fix: complete retail parity stability pass
2026-08-28 20:01:39 +02:00

92 lines
4.2 KiB
C#

namespace AcDream.Core.Net.Transport;
/// <summary>
/// Unconditional reliable-transport counters. Increment sites are NOT
/// probe-gated — the counters are plain field writes and always current, so
/// a later probe (N5's <c>[net-tick]</c> extension) or a connected gate can
/// read them without having been armed in advance. Printing stays
/// probe-gated at the call sites that choose to surface them.
/// </summary>
internal sealed class TransportStats
{
/// <summary>Checksum-valid post-negotiation datagrams received. Used by
/// retail's 2-second/40-sample link-status loss window.</summary>
public long PacketsReceived;
/// <summary>Datagrams successfully emitted after transport negotiation.
/// Includes reliable traffic, retransmits, cumulative ACKs, and NAKs,
/// matching retail's packet-level denominator.</summary>
public long PacketsSent;
/// <summary>Datagrams re-emitted in response to a server NAK.</summary>
public long ResendsSent;
/// <summary>Inbound packets carrying <c>RequestRetransmit</c>.</summary>
public long NakRequestsReceived;
/// <summary>
/// NAKed ids no longer (or never) in the sent-packet cache, dropped
/// silently instead of answering retail's <c>RejectRetransmit</c>
/// (divergence register TS-57 — ACE no-ops the reject, and the
/// standalone unsequenced form would trip ACE's watermark hole).
/// </summary>
public long UncachedNakIds;
/// <summary>Inbound <c>AckSequence</c> values folded into the watermark
/// (explicit acks plus the NAK <c>ids[0]</c> implicit ack).</summary>
public long AcksConsumed;
/// <summary>N2: inbound duplicates of already-decoded packets, dropped
/// at zero keystream cost (encrypted, at/below the watermark, no parked
/// key — <c>ProcessNewSeqNum @ 0x00544690</c>).</summary>
public long InboundDupsDropped;
/// <summary>N2: inbound packets past the wrap-safe
/// <c>watermark + 0x7FFF</c> horizon
/// (<c>SeqIDSanityCheck @ 0x00543A20</c>).</summary>
public long InboundSanityDrops;
/// <summary>N2: inbound packets whose checksum failed verification
/// after admission (a sequenced encrypted failure also re-parks its
/// consumed key for the retransmission).</summary>
public long ChecksumFailures;
/// <summary>N2: inbound keystream words parked in the NAK set — one per
/// gap-walked missing id (<c>ReceiverData::AddNakked @ 0x00549240</c>
/// pre-draw) plus one per checksum-failure re-park.</summary>
public long KeysParked;
/// <summary>N3: cumulative <c>AckSequence</c> packets emitted by the
/// 2.0 s sweep (<c>SharedNet::EnqueuePak @ 0x00543B10</c> — retail's
/// only ack construction site; there is no per-packet ack).</summary>
public long AcksSent;
/// <summary>N4: <c>RequestRetransmit</c> packets emitted by the 0.6 s
/// NAK branch (<c>SharedNet::EnqueueNaks @ 0x00543BD0</c> →
/// <c>ReceiverData::GetNaks @ 0x005490C0</c>, ≤114 ids each).</summary>
public long NaksSent;
/// <summary>Total missing sequence ids carried by emitted NAKs. Retail's
/// <c>CLinkStatusSnapshot::nPktsNAKed</c> counts missing packets, not the
/// number of control datagrams used to request them.</summary>
public long NakIdsSent;
/// <summary>N4: mis-parked keystream words reclaimed from validated
/// cleartext <c>RejectRetransmit</c> sequences (the AD-51 ACE
/// adaptation; always zero against a retail server).</summary>
public long RejectWordsReclaimed;
/// <summary>N5: inbound packets carrying <c>RejectRetransmit</c> — the
/// server abandoned ids we NAKed (its cache pruned them). The
/// <c>rej-in/s</c> field of <c>[net-tick]</c>.</summary>
public long RejectsReceived;
/// <summary>Live sent-packet cache depth — the N5 watchdog value
/// (<c>cache=N</c> in <c>[net-tick]</c>; the cache is unbounded like
/// retail's, so depth is the health signal, not a cap).</summary>
public int CacheDepth => CacheDepthSource?.Invoke() ?? 0;
/// <summary>Wired by <see cref="ReliableTransport"/> to the store's
/// <c>Count</c>.</summary>
internal Func<int>? CacheDepthSource { get; set; }
}