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"; }