namespace AcDream.Core.Net;
///
/// Direction mask for the N5 LossyTransportDecorator
/// (ACDREAM_NET_DROP_DIR): drop outbound datagrams, inbound
/// datagrams, or both.
///
public enum NetDropDirection
{
Out,
In,
Both,
}
///
/// Diagnostic owner for the ACDREAM_PROBE_NET probe family (#260).
/// Read once at startup, following the PhysicsDiagnostics pattern.
///
///
/// When enabled, four probe line families are emitted:
///
/// - [net-out] — one line per outbound reliable game message at the
/// WorldSession.SendGameMessage chokepoint: opcode, game-action type +
/// sequence (when the body is a 0xF7B1 GameAction), fragment/packet sequence,
/// managed thread id, and session state. An exception escaping the wire write
/// additionally emits [net-out-EX] via an exception filter (log
/// without catching — behavior is unchanged).
/// - [net-tick] — a once-per-second cadence summary from
/// WorldSession.Tick: inbound datagrams/s, remaining queue depth,
/// budget-break count, worst inter-tick gap (= worst frame stall as seen by
/// the net pump), outbound sends/s, acks/s, and — the N5 loss-observability
/// extension — per-second reliable-transport rates (resends, NAKs out/in,
/// rejects in, duplicate drops, parked keystream words, AD-51 reclaims)
/// plus the two instantaneous depths (sent-packet cache, inbound NAK set).
/// The counters themselves increment unconditionally in
/// TransportStats; only the string work is gated here.
/// - [net-final] — one cumulative TransportStats summary
/// emitted at WorldSession.Dispose, so a connected gate (N5's loss
/// gate) can assert exact totals instead of reconstructing them from
/// rounded per-second rates.
/// - [cmd-gate] — one line per generation-gated runtime command
/// REJECTION in CurrentGameRuntimeCommandAdapter.Validate (status,
/// expected vs view generation, lifecycle, IsInWorld) plus the combat-toggle
/// result. These rejections are otherwise completely silent, which is what
/// let #260's wedge hide.
///
/// Zero steady-state cost when off: every site is behind this single bool.
///
///
public static class NetDiagnostics
{
///
/// ACDREAM_PROBE_NET=1 — #260 outbound/command-gate probe family.
///
public static bool ProbeNet { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_NET") == "1";
///
/// ACDREAM_NET_DROP_PCT (int 0–100, default 0 = off) — N5
/// deterministic loss injection. When > 0 the session's DEFAULT
/// transport factory wraps the socket transport in
/// LossyTransportDecorator; at 0 the decorator is structurally
/// absent (never constructed). Out-of-range or unparsable values read
/// as 0 — a mistyped variable must never inject loss.
///
public static int NetDropPercent { get; set; } =
ParseDropPercent(
Environment.GetEnvironmentVariable("ACDREAM_NET_DROP_PCT"));
///
/// ACDREAM_NET_DROP_SEED (int, default 1) — the decorator's PRNG
/// seed. Same seed ⇒ identical per-direction drop pattern.
///
public static int NetDropSeed { get; set; } =
int.TryParse(
Environment.GetEnvironmentVariable("ACDREAM_NET_DROP_SEED"),
out int seed)
? seed
: 1;
///
/// ACDREAM_NET_DROP_DIR (out | in | both,
/// default both) — which directions the decorator drops.
///
public static NetDropDirection NetDropDir { get; set; } =
ParseDropDirection(
Environment.GetEnvironmentVariable("ACDREAM_NET_DROP_DIR"));
internal static int ParseDropPercent(string? value) =>
int.TryParse(value, out int percent) && percent is >= 0 and <= 100
? percent
: 0;
internal static NetDropDirection ParseDropDirection(string? value) =>
value?.ToLowerInvariant() switch
{
"out" => NetDropDirection.Out,
"in" => NetDropDirection.In,
_ => NetDropDirection.Both,
};
///
/// ACDREAM_PROBE_REVEAL=1 — #260 reveal-stall probe: while a
/// reveal destination's composite warmup is incomplete, emit one
/// [composite-warmup] line per second naming the pending queue
/// depth, scan state, upload-budget gate, and the first few unresolved
/// GfxObj ids. The two permanent-stall shapes (a mesh id that never
/// resolves vs. an upload budget that never reopens) are otherwise
/// indistinguishable and invisible.
///
public static bool ProbeReveal { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_REVEAL") == "1";
}