A replicant is measured in its own step
Three previous attempts at "is the watched pod's motion uniform" all
sampled it from somewhere else - the camera's step grid, or an arriving
packet's timestamp - and two independent clocks alias against each other
whatever the game is doing. Those numbers could never separate a real
hitch from the measurement's own beat, and each of them cost a deploy to
find that out.
This one has a single frame of reference: consecutive steps of the entity
being asked about, taken inside Mover::DeadReckon, which IS a replicant's
own per-step performance.
It also reports the mechanism rather than only the symptom. percent is how
far each step moves toward the projected position:
percent = time_slice / ((nextUpdate - lastPerformance) + time_slice)
so it depends on nextUpdate being a decent guess at when the next packet
lands. A poor guess makes the fraction swing, and a swinging fraction is
uneven motion however clean the packets were. The trace reports its range,
how many steps blended rather than snapped, and spikes and stalls against
the entity's own running mean.
One entity only, the first replicant seen, because the counters are shared
and a full grid would blend into noise.
What confirms: spikes or stalls in the entity's OWN steps, or a percent
range that swings. Either is real, because there is no second clock here to
blame. What refutes: uniform steps and a steady percent - then a replicant's
motion is fine and the tick is in presentation, and the remaining suspects
are frame delivery and the map raster.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+113
@@ -12,6 +12,15 @@
|
||||
#include "app.h"
|
||||
#include "notation.h"
|
||||
|
||||
//
|
||||
// The blend fraction the last dead-reckoned step used, and whether it
|
||||
// blended at all rather than snapping. Only read by the RP412CAMLOG trace
|
||||
// in Mover::DeadReckon, which needs them from the branch that computes
|
||||
// them a few lines earlier.
|
||||
//
|
||||
static Logical gLastLerpUsed = False;
|
||||
static Scalar gLastPercent = 0.0f;
|
||||
|
||||
//#############################################################################
|
||||
//############################### Mover #################################
|
||||
//#############################################################################
|
||||
@@ -513,6 +522,10 @@ void
|
||||
Scalar percent =
|
||||
time_slice / ((nextUpdate - lastPerformance) + time_slice);
|
||||
|
||||
// for the RP412CAMLOG trace at the end of this function
|
||||
gLastLerpUsed = True;
|
||||
gLastPercent = percent;
|
||||
|
||||
//
|
||||
//------------------------------------------
|
||||
// Do a spherical lerp on the angular motion
|
||||
@@ -562,6 +575,7 @@ void
|
||||
}
|
||||
else
|
||||
{
|
||||
gLastLerpUsed = False; // snapped, not blended
|
||||
localOrigin = projectedOrigin;
|
||||
worldLinearVelocity = projectedVelocity.linearMotion;
|
||||
localVelocity.angularMotion = projectedVelocity.angularMotion;
|
||||
@@ -581,6 +595,105 @@ void
|
||||
localToWorld = localOrigin;
|
||||
}
|
||||
UpdateLocalMotion();
|
||||
|
||||
//
|
||||
// RP412CAMLOG: is a replicant's motion actually uniform?
|
||||
//
|
||||
// Measured HERE, in the replicant's own step, and nowhere else.
|
||||
// Every previous attempt at this question sampled from another
|
||||
// clock - the camera's step grid, or an arriving packet's
|
||||
// timestamp - and two independent clocks alias against each other
|
||||
// whatever the game is doing, so those numbers could never
|
||||
// separate a real hitch from the measurement's own beat. This one
|
||||
// has a single frame of reference: consecutive steps of the entity
|
||||
// being asked about.
|
||||
//
|
||||
// percent is the whole mechanism above: it is how far this step
|
||||
// moves toward the projected position, and it depends on
|
||||
// nextUpdate being a decent guess at when the next packet lands.
|
||||
// If that guess is poor the fraction swings, and swinging fraction
|
||||
// is uneven motion no matter how clean the packets were.
|
||||
//
|
||||
// One entity only - the first replicant seen - because these
|
||||
// counters are shared and a grid full of pods would blend into
|
||||
// noise.
|
||||
//
|
||||
if (RPCameraLog())
|
||||
{
|
||||
static EntityID watched = EntityID::Null;
|
||||
static Logical latched = False;
|
||||
|
||||
if (!latched)
|
||||
{
|
||||
latched = True;
|
||||
watched = GetEntityID();
|
||||
}
|
||||
if (watched == GetEntityID())
|
||||
{
|
||||
static Scalar next_say = 0.0f;
|
||||
static Point3D last_pos(0.0f, 0.0f, 0.0f);
|
||||
static Logical have_last = False;
|
||||
static int steps = 0;
|
||||
static int spikes = 0;
|
||||
static int stalls = 0;
|
||||
static int lerped = 0;
|
||||
static Scalar mean_step = 0.0f;
|
||||
static Scalar min_percent = 1.0f;
|
||||
static Scalar max_percent = 0.0f;
|
||||
|
||||
++steps;
|
||||
if (have_last)
|
||||
{
|
||||
Vector3D moved;
|
||||
moved.Subtract(localOrigin.linearPosition, last_pos);
|
||||
Scalar distance = moved.Length();
|
||||
|
||||
if (distance > 50.0f)
|
||||
{
|
||||
mean_step = 0.0f; // respawn, not motion
|
||||
}
|
||||
else if (mean_step > 0.01f)
|
||||
{
|
||||
Scalar ratio = distance / mean_step;
|
||||
if (ratio > 2.5f) { ++spikes; }
|
||||
else if (ratio < 0.4f) { ++stalls; }
|
||||
mean_step = mean_step * 0.9f + distance * 0.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
mean_step = distance;
|
||||
}
|
||||
}
|
||||
last_pos = localOrigin.linearPosition;
|
||||
have_last = True;
|
||||
|
||||
if ((Scalar) Now() >= next_say)
|
||||
{
|
||||
if (next_say > 0.0f)
|
||||
{
|
||||
DEBUG_STREAM << "CamLog: replicant motion - " << steps
|
||||
<< " own steps, " << spikes << " spike(s), "
|
||||
<< stalls << " stall(s), " << lerped
|
||||
<< " lerped, percent " << min_percent << ".."
|
||||
<< max_percent << ", mean step " << mean_step
|
||||
<< "m\n" << std::flush;
|
||||
}
|
||||
next_say = ((Scalar) Now()) + 5.0f;
|
||||
steps = 0;
|
||||
spikes = 0;
|
||||
stalls = 0;
|
||||
lerped = 0;
|
||||
min_percent = 1.0f;
|
||||
max_percent = 0.0f;
|
||||
}
|
||||
if (gLastLerpUsed)
|
||||
{
|
||||
++lerped;
|
||||
if (gLastPercent < min_percent) { min_percent = gLastPercent; }
|
||||
if (gLastPercent > max_percent) { max_percent = gLastPercent; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user