A static diagnostics utility that samples and reports the distance between HitPosition and EndPosition for penetrated bodies to determine whether that distance represents a trace radius or actual thickness. It accumulates count, min/max/mean, histogram bins, and exposes a console command nz_pen_probe that prints or resets the collected statistics.
using Sandbox;
using System;
namespace NZombies;
/// <summary>
/// PEN/PROBE — what the penetration budget actually charges per body.
///
/// ⛔ THIS EXISTS BECAUSE TWO READINGS OF ONE LINE DISAGREE, AND THE ANSWER CHANGES GAMEPLAY.
/// `HitScan` spends the budget as:
///
/// penBudget -= bulletTr.EndPosition.Distance( bulletTr.HitPosition ) + 1.0f;
///
/// `DtapAugments.BodyDepth` says that distance is "the THICKNESS ACTUALLY CROSSED", about ten
/// units for a torso, and calibrates its "+8 zombies" promise on 11 units per body. Reading the
/// trace API instead suggests `HitPosition` is the contact point on the surface while `EndPosition`
/// is where the swept shape's centre came to rest — which would make the distance roughly the
/// RADIUS, about 2, not a thickness at all.
///
/// ⛔ AND THE BULLET IS NOW A RAY, WHICH MAKES THE DIFFERENCE URGENT. At radius 0 those two points
/// should coincide, so the distance collapses toward zero and the budget is charged only the 1.0
/// surcharge per body. If the radius reading is the right one, pierce depth just went from about
/// three bodies to about nine — a large balance change nobody asked for, arriving silently.
///
/// ⚠️ MEASURES, CHANGES NOTHING. Every value is recorded and reported; none is fed back.
///
/// ⚠️ ALLOCATION-FREE AND ALWAYS ON. Running count/min/max/sum plus a coarse histogram, all in
/// fields — this sits on the hottest line in the damage path, so it must not become the thing worth
/// profiling. Compare CpuScope, which measured its own overhead at 179ns and was still fine.
/// </summary>
public static class PenProbe
{
static int _n;
static float _min = float.MaxValue;
static float _max;
static double _sum;
/// <summary>Buckets: <0.5, <1.5, <3, <6, <12, <25, 25+.</summary>
static readonly int[] _bins = new int[7];
static readonly float[] Edges = { 0.5f, 1.5f, 3f, 6f, 12f, 25f };
static readonly string[] Labels =
{
"< 0.5 (a ray — the two points coincide)",
"< 1.5",
"< 3 (about the old sphere radius)",
"< 6",
"< 12 (about one torso — the BodyDepth reading)",
"< 25",
"25+",
};
/// <summary>
/// Record one body's charge against the budget.
///
/// ⚠️ CALLED WITH THE RAW DISTANCE, NOT THE CHARGE. The `+ 1.0f` surcharge is added by the
/// caller and is not in question; what is in question is the term before it.
/// </summary>
public static void Sample( float distance )
{
_n++;
_sum += distance;
if ( distance < _min ) _min = distance;
if ( distance > _max ) _max = distance;
for ( int i = 0; i < Edges.Length; i++ )
{
if ( distance < Edges[i] ) { _bins[i]++; return; }
}
_bins[6]++;
}
/// <summary>`nz_pen_probe [reset]` — what the budget has been charging per body.</summary>
[ConCmd( "nz_pen_probe" )]
public static void Report( string arg = "" )
{
if ( arg.Equals( "reset", StringComparison.OrdinalIgnoreCase ) )
{
_n = 0; _min = float.MaxValue; _max = 0f; _sum = 0;
Array.Clear( _bins, 0, _bins.Length );
Log.Info( "[nz-pen] cleared" );
return;
}
if ( _n == 0 )
{
Log.Info( "[nz-pen] no samples yet — shoot something that penetrates, then run this" );
return;
}
var mean = (float)(_sum / _n);
Log.Info( $"[nz-pen] EndPosition.Distance( HitPosition ) over {_n} penetrated bodies:" );
Log.Info( $"[nz-pen] min {_min:0.###} mean {mean:0.###} max {_max:0.###}" );
for ( int i = 0; i < _bins.Length; i++ )
{
if ( _bins[i] == 0 ) continue;
Log.Info( $"[nz-pen] {Labels[i],-45} {_bins[i],6} ({100f * _bins[i] / _n:0.#}%)" );
}
// ⚠️ THE VERDICT IS STATED, because the whole point is to settle which of two readings is
// right — and a table of numbers invites the same argument all over again next week.
Log.Info( mean < 0.5f
? "[nz-pen] VERDICT: near zero — the budget charges ~1.0 per body (the surcharge alone),"
+ " so PenetrationDepth is a BODY COUNTER, not a depth. DtapAugments.BodyDepth = 11"
+ " is calibrated against something this is not."
: mean < 4f
? "[nz-pen] VERDICT: about the trace radius — the distance is a shape artefact, not a"
+ " thickness. Pierce depth therefore CHANGES with nz_trace_radius, which is a"
+ " coupling nobody intended."
: "[nz-pen] VERDICT: large enough to be a real thickness — DtapAugments.BodyDepth's"
+ " reading holds and the budget behaves as documented." );
Log.Info( $"[nz-pen] (trace radius is currently {SWB.Base.Weapon.TraceRadius:0.##};"
+ " bodies-per-bullet is n_dmg_hit / n_shot_bullet in the perf log)" );
}
}