WIP checkpoint: TCP_NODELAY + dense-send + BT_JIT/BT_ANIM probes + FOGDAY test egg (task #50 investigation)
Session-in-progress peer-motion work, checkpointed before bisecting the 07-13/07-14 gait regression. Contains: TCP_NODELAY on game sockets (L4NET), every-frame dense position send while moving + came-to-rest/REST send + per-frame BT_JIT/BT_ANIM smoothness probes (mech4). bodyTargetSpeed feed reverted to derived-velocity default. MOVER.cpp spline experiment already reverted. NOT a fix -- a checkpoint. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
94647dd378
commit
d5d512e087
@@ -0,0 +1,244 @@
|
|||||||
|
[mission]
|
||||||
|
adventure=BattleTech
|
||||||
|
map=arena1
|
||||||
|
scenario=freeforall
|
||||||
|
time=day
|
||||||
|
weather=fog
|
||||||
|
temperature=27
|
||||||
|
length=600
|
||||||
|
[ordinals]
|
||||||
|
bitmap=Ordinal::BitMap::1
|
||||||
|
bitmap=Ordinal::BitMap::2
|
||||||
|
bitmap=Ordinal::BitMap::3
|
||||||
|
bitmap=Ordinal::BitMap::4
|
||||||
|
[Ordinal::BitMap::1]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=000038000003C000001FF00000000F00
|
||||||
|
bitmap=0000F8000003C000003FF80000000F00
|
||||||
|
bitmap=0001F8000003C00000707C0000000F00
|
||||||
|
bitmap=0001F8000003C00000603C0000000F00
|
||||||
|
bitmap=00007801FC0FF00000003C3DF807FF00
|
||||||
|
bitmap=00007803FE0FF00000003C3FFC0FFF00
|
||||||
|
bitmap=00007803C703C00000003C3E3C1F0F00
|
||||||
|
bitmap=000078078303C0000000783C1E1E0F00
|
||||||
|
bitmap=000078078003C0000000783C1E1E0F00
|
||||||
|
bitmap=00007807C003C0000000F03C1E1E0F00
|
||||||
|
bitmap=00007807F003C0000001E03C1E1E0F00
|
||||||
|
bitmap=00007803FC03C0000003C03C1E1E0F00
|
||||||
|
bitmap=00007801FE03C0000007803C1E1E0F00
|
||||||
|
bitmap=000078007F03C000000F003C1E1E0F00
|
||||||
|
bitmap=000078001F03C000001E003C1E1E0F00
|
||||||
|
bitmap=000078000F03C000003C003C1E1E0F00
|
||||||
|
bitmap=000078060F03C0000078003C1E1E0F00
|
||||||
|
bitmap=000078071E03E0000078003C1E1F1F00
|
||||||
|
bitmap=00007803FE01F000007FFC3C1E0FFF00
|
||||||
|
bitmap=00007801FC00F000007FFC3C1E07EF00
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=128
|
||||||
|
y=32
|
||||||
|
width=8
|
||||||
|
[Ordinal::BitMap::2]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=001FFF0000003C0000003C03C0780000
|
||||||
|
bitmap=001FFF0000003C0000007C03C0780000
|
||||||
|
bitmap=00000E0000003C000000FC03C0780000
|
||||||
|
bitmap=00003C0000003C000001BC03C0780000
|
||||||
|
bitmap=0000700F3E1FFC000003BC0FF07BF000
|
||||||
|
bitmap=0001E00F7E3FFC0000073C0FF07FF800
|
||||||
|
bitmap=0003800FFE7C3C0000063C03C07C7800
|
||||||
|
bitmap=0007F80FFE783C00000C3C03C0783C00
|
||||||
|
bitmap=0007FE0F80783C0000183C03C0783C00
|
||||||
|
bitmap=00001E0F00783C0000383C03C0783C00
|
||||||
|
bitmap=00000F0F00783C0000703C03C0783C00
|
||||||
|
bitmap=00000F0F00783C00007FFF03C0783C00
|
||||||
|
bitmap=00000F0F00783C00007FFF03C0783C00
|
||||||
|
bitmap=00000F0F00783C0000003C03C0783C00
|
||||||
|
bitmap=00000F0F00783C0000003C03C0783C00
|
||||||
|
bitmap=00000F0F00783C0000003C03C0783C00
|
||||||
|
bitmap=00180F0F00783C0000003C03C0783C00
|
||||||
|
bitmap=001C1F0F007C7C0000003C03E0783C00
|
||||||
|
bitmap=000FFE0F003FFC0000003C01F0783C00
|
||||||
|
bitmap=0007FC0F001FBC0000003C00F0783C00
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=128
|
||||||
|
y=32
|
||||||
|
width=8
|
||||||
|
[Ordinal::BitMap::3]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=001FFF03C07800000000FC03C0780000
|
||||||
|
bitmap=001FFF03C07800000003FC03C0780000
|
||||||
|
bitmap=001E0003C07800000007C003C0780000
|
||||||
|
bitmap=001E0003C0780000000F0003C0780000
|
||||||
|
bitmap=001E000FF07BF000000F000FF07BF000
|
||||||
|
bitmap=001E000FF07FF800001E000FF07FF800
|
||||||
|
bitmap=001E0003C07C7800001E0003C07C7800
|
||||||
|
bitmap=001FFC03C0783C00001EFC03C0783C00
|
||||||
|
bitmap=001FFE03C0783C00001FFE03C0783C00
|
||||||
|
bitmap=00001F03C0783C00001F1F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00000F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00180F03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=001C1F03E0783C00001F1F03E0783C00
|
||||||
|
bitmap=000FFE01F0783C00000FFE01F0783C00
|
||||||
|
bitmap=0007FC00F0783C000007FC00F0783C00
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=128
|
||||||
|
y=32
|
||||||
|
width=8
|
||||||
|
[Ordinal::BitMap::4]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=001FFF03C07800000007FC03C0780000
|
||||||
|
bitmap=001FFF03C0780000000FFE03C0780000
|
||||||
|
bitmap=00000F03C0780000001F1F03C0780000
|
||||||
|
bitmap=00000F03C0780000001E0F03C0780000
|
||||||
|
bitmap=00000F0FF07BF000001E0F0FF07BF000
|
||||||
|
bitmap=00001F0FF07FF800001E0F0FF07FF800
|
||||||
|
bitmap=00001E03C07C7800001E0F03C07C7800
|
||||||
|
bitmap=00003E03C0783C00001E0F03C0783C00
|
||||||
|
bitmap=00003C03C0783C00000F1E03C0783C00
|
||||||
|
bitmap=00003C03C0783C000007FC03C0783C00
|
||||||
|
bitmap=00007803C0783C000007FC03C0783C00
|
||||||
|
bitmap=00007803C0783C00000F1E03C0783C00
|
||||||
|
bitmap=00007803C0783C00001E0F03C0783C00
|
||||||
|
bitmap=0000F003C0783C00001E0F03C0783C00
|
||||||
|
bitmap=0000F003C0783C00001E0F03C0783C00
|
||||||
|
bitmap=0000F003C0783C00001E0F03C0783C00
|
||||||
|
bitmap=0000F003C0783C00001E0F03C0783C00
|
||||||
|
bitmap=0000F003E0783C00000F1E03E0783C00
|
||||||
|
bitmap=0000F001F0783C00000FFE01F0783C00
|
||||||
|
bitmap=0000F000F0783C000007FC00F0783C00
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=128
|
||||||
|
y=32
|
||||||
|
width=8
|
||||||
|
[pilots]
|
||||||
|
pilot=127.0.0.1:1502
|
||||||
|
pilot=127.0.0.1:1602
|
||||||
|
[127.0.0.1:1502]
|
||||||
|
hostType=0
|
||||||
|
advancedDamage=1
|
||||||
|
loadzones=1
|
||||||
|
name=Aeolus
|
||||||
|
bitmapindex=1
|
||||||
|
experience=expert
|
||||||
|
badge=VGL
|
||||||
|
patch=Yellow
|
||||||
|
role=Role::Default
|
||||||
|
dropzone=one
|
||||||
|
vehicle=bhk1
|
||||||
|
vehicleValue=1000
|
||||||
|
color=White
|
||||||
|
[127.0.0.1:1602]
|
||||||
|
hostType=0
|
||||||
|
advancedDamage=1
|
||||||
|
loadzones=1
|
||||||
|
name=Boreas
|
||||||
|
bitmapindex=2
|
||||||
|
experience=expert
|
||||||
|
badge=VGL
|
||||||
|
patch=Yellow
|
||||||
|
role=Role::Default
|
||||||
|
dropzone=one
|
||||||
|
vehicle=ava1
|
||||||
|
vehicleValue=1000
|
||||||
|
color=Red
|
||||||
|
[largebitmap]
|
||||||
|
bitmap=BitMap::Large::Aeolus
|
||||||
|
[BitMap::Large::Aeolus]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=000003FE0000000001E0000000000000
|
||||||
|
bitmap=000007FF0000000001E0000000000000
|
||||||
|
bitmap=00000F8F8000000001E0000000000000
|
||||||
|
bitmap=00000F078000000001E0000000000000
|
||||||
|
bitmap=00000F0781FF00FF81E0F0781FC00000
|
||||||
|
bitmap=00000F0783FF81FFC1E0F0783FE00000
|
||||||
|
bitmap=00000F0787C7C3E3E1E0F0783C700000
|
||||||
|
bitmap=00000F078783C3C1E1E0F07878300000
|
||||||
|
bitmap=00000F078783C3C1E1E0F07878000000
|
||||||
|
bitmap=00000FFF8783C3C1E1E0F0787C000000
|
||||||
|
bitmap=00000FFF8783C3C1E1E0F0787F000000
|
||||||
|
bitmap=00000F0787FFC3C1E1E0F0783FC00000
|
||||||
|
bitmap=00000F0787FFC3C1E1E0F0781FE00000
|
||||||
|
bitmap=00000F07878003C1E1E0F07807F00000
|
||||||
|
bitmap=00000F07878003C1E1E0F07801F00000
|
||||||
|
bitmap=00000F07878003C1E1E0F07800F00000
|
||||||
|
bitmap=00000F078780C3C1E1E0F07860F00000
|
||||||
|
bitmap=00000F0787C1C3E3E1E078F871E00000
|
||||||
|
bitmap=00000F0783FF81FFC1E07FF83FE00000
|
||||||
|
bitmap=00000F0781FF00FF81E03F781FC00000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=128
|
||||||
|
y=32
|
||||||
|
width=8
|
||||||
|
[smallbitmap]
|
||||||
|
bitmap=BitMap::Small::Aeolus
|
||||||
|
[BitMap::Small::Aeolus]
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
bitmap=0000000000000000003E00000C000000
|
||||||
|
bitmap=006300000C00000000631F0F8CC63C00
|
||||||
|
bitmap=00633198CCC66200007F3198CCC66000
|
||||||
|
bitmap=00633F98CCC6780000633018CCC61E00
|
||||||
|
bitmap=00633018CCC6060000633098CCC64600
|
||||||
|
bitmap=00631F0F8C7E3C000000000000000000
|
||||||
|
bitmap=00000000000000000000000000000000
|
||||||
|
x=64
|
||||||
|
y=16
|
||||||
|
width=4
|
||||||
|
[Role::Default]
|
||||||
|
model=dfltrole
|
||||||
|
[Role::NoReturn]
|
||||||
|
model=noretun
|
||||||
@@ -2118,6 +2118,12 @@ Logical L4NetworkManager::CheckBuffers(NetworkPacket *network_packet)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// TCP_NODELAY on the accepted GAME socket (not the console):
|
||||||
|
// without it Nagle coalesces the inbound per-frame update
|
||||||
|
// records into bursts -> the peer is received in lurches.
|
||||||
|
BOOL gameNoDelay = TRUE;
|
||||||
|
if (setsockopt(tempSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&gameNoDelay, sizeof(gameNoDelay)))
|
||||||
|
DEBUG_STREAM << "WARN: could not set TCP_NODELAY on accepted game socket; setsockopt() failed with " << WSAGetLastError() << "\n" << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote_host->SetNetworkSocket(tempSocket);
|
remote_host->SetNetworkSocket(tempSocket);
|
||||||
@@ -2798,6 +2804,18 @@ SOCKET L4NetworkManager::OpenConnection(
|
|||||||
WSACleanup();
|
WSACleanup();
|
||||||
PostQuitMessage(AbortExitCodeID);
|
PostQuitMessage(AbortExitCodeID);
|
||||||
}
|
}
|
||||||
|
// TCP_NODELAY: disable Nagle so the small per-frame update records ship
|
||||||
|
// immediately instead of being coalesced. With Nagle on (the default),
|
||||||
|
// Nagle + delayed-ACK batch the tiny position packets into ~40-200ms
|
||||||
|
// bursts, so a peer that moves at a steady speed is RECEIVED in lurches
|
||||||
|
// (measured: dead-reckoned ground speed swinging 3x per 0.25s window).
|
||||||
|
// The pod net carries steady real-time state where latency, not
|
||||||
|
// throughput, is what matters -- exactly the case NODELAY is for.
|
||||||
|
{
|
||||||
|
BOOL noDelay = TRUE;
|
||||||
|
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&noDelay, sizeof(noDelay)))
|
||||||
|
DEBUG_STREAM << "WARN: could not set TCP_NODELAY on active socket; setsockopt() failed with " << WSAGetLastError() << "\n" << std::flush;
|
||||||
|
}
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
else if(connection_type == NETNUB_TCP_LISTEN)
|
else if(connection_type == NETNUB_TCP_LISTEN)
|
||||||
|
|||||||
+112
-27
@@ -1930,6 +1930,44 @@ void
|
|||||||
DeadReckon(dt); // engine: reckoner + lerp
|
DeadReckon(dt); // engine: reckoner + lerp
|
||||||
localToWorld = localOrigin;
|
localToWorld = localOrigin;
|
||||||
|
|
||||||
|
// Lightweight dead-reckon smoothness probe (one flush/sec, cheap).
|
||||||
|
// PATH length (sum of |per-frame step|) vs NET displacement reveals
|
||||||
|
// jitter: a smooth walk has path==net; oscillation inflates path while
|
||||||
|
// net stays small. avgHorizon is the lerp target distance in time.
|
||||||
|
if (getenv("BT_JIT"))
|
||||||
|
{
|
||||||
|
static bool s_jinit = false;
|
||||||
|
static Point3D s_jprev, s_jnetA;
|
||||||
|
static float s_jacc = 0.0f, s_jpath = 0.0f, s_jmax = 0.0f, s_jhzn = 0.0f;
|
||||||
|
static int s_jfr = 0;
|
||||||
|
if (s_jinit)
|
||||||
|
{
|
||||||
|
const float dx = (float)(localOrigin.linearPosition.x - s_jprev.x);
|
||||||
|
const float dz = (float)(localOrigin.linearPosition.z - s_jprev.z);
|
||||||
|
const float step = sqrtf(dx * dx + dz * dz);
|
||||||
|
s_jpath += step;
|
||||||
|
if (step > s_jmax) s_jmax = step;
|
||||||
|
}
|
||||||
|
else { s_jnetA = localOrigin.linearPosition; s_jinit = true; }
|
||||||
|
s_jprev = localOrigin.linearPosition;
|
||||||
|
s_jhzn += (float)(nextUpdate - lastPerformance);
|
||||||
|
s_jfr++; s_jacc += dt;
|
||||||
|
if (s_jacc >= 1.0f)
|
||||||
|
{
|
||||||
|
const float ndx = (float)(localOrigin.linearPosition.x - s_jnetA.x);
|
||||||
|
const float ndz = (float)(localOrigin.linearPosition.z - s_jnetA.z);
|
||||||
|
const float net = sqrtf(ndx * ndx + ndz * ndz);
|
||||||
|
DEBUG_STREAM << "[repljit] frames=" << s_jfr
|
||||||
|
<< " path=" << s_jpath << " net=" << net
|
||||||
|
<< " ratio=" << (net > 0.001f ? s_jpath / net : 0.0f)
|
||||||
|
<< " maxStep=" << s_jmax << " avgStep=" << (s_jpath / s_jfr)
|
||||||
|
<< " avgHorizon=" << (s_jhzn / s_jfr)
|
||||||
|
<< "\n" << std::flush;
|
||||||
|
s_jacc = 0.0f; s_jpath = 0.0f; s_jmax = 0.0f; s_jhzn = 0.0f;
|
||||||
|
s_jfr = 0; s_jnetA = localOrigin.linearPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// REPLICANT GAIT (task #50): animate the peer mech's legs at the
|
// REPLICANT GAIT (task #50): animate the peer mech's legs at the
|
||||||
// REPLICATED speed -- without this the replicant slides around as a
|
// REPLICATED speed -- without this the replicant slides around as a
|
||||||
// frozen statue. The master publishes worldLinearVelocity in every
|
// frozen statue. The master publishes worldLinearVelocity in every
|
||||||
@@ -1946,33 +1984,37 @@ void
|
|||||||
MechControlsMapper *replMppr = MappingMapper(); // roster slot 0 (task #7)
|
MechControlsMapper *replMppr = MappingMapper(); // roster slot 0 (task #7)
|
||||||
if (!IsMechDestroyed() && replMppr != 0)
|
if (!IsMechDestroyed() && replMppr != 0)
|
||||||
{
|
{
|
||||||
const Vector3D &wv = updateVelocity.linearMotion;
|
// Feed the leg SM the REPLICATED COMMANDED speed (bodyTargetSpeed):
|
||||||
float spd = sqrtf((float)(wv.x * wv.x + wv.z * wv.z));
|
// the master's OWN mppr->speedDemand, carried in every pose (type-0)
|
||||||
UnitVector zAxR;
|
// and speed (type-2) record (mech.cpp:1833/1841). This is the
|
||||||
localToWorld.GetFromAxis(Z_Axis, &zAxR);
|
// IDENTICAL input the master's own leg SM consumes, so the replicant
|
||||||
const float fdot = -((float)wv.x * (float)zAxR.x
|
// selects the same gait state and RAMPS its cadence through accel /
|
||||||
+ (float)wv.z * (float)zAxR.z); // mech faces -Z
|
// decel exactly as the master does -- the legs stay in sync with the
|
||||||
Scalar sd = (fdot < 0.0f) ? -spd : spd;
|
// motion. The earlier feed derived the ACTUAL velocity from
|
||||||
// WALK-ENTRY FLOOR (user-reported "slides forward before it steps",
|
// updateVelocity, but a mech's forward walk velocity (~walkStrideLength)
|
||||||
// root-caused 2026-07-14 from a per-frame [replmov] trace): the leg
|
// sits BELOW standSpeed, so it never cleared the stand->walk gate; the
|
||||||
// SM enters walk only when `standSpeed < commandedSpeed`, but a mech's
|
// floor hack that fixed THAT then pinned the cadence flat during
|
||||||
// forward WALK velocity == walkStrideLength which sits BELOW standSpeed
|
// accel/decel -- the reported stutter/skip glitch. bodyTargetSpeed is
|
||||||
// (bhk1: walk 6.13 < stand ~6.8). The master clears the gate because
|
// signed (negative == reverse), so reverse needs no special case.
|
||||||
// it feeds the leg SM its COMMANDED throttle speed (>> standSpeed); the
|
// (BT_REPL_VEL forces the old derived-velocity feed for A/B compare.)
|
||||||
// replicant feeds the DERIVED actual velocity, which never crosses the
|
static const int s_useCmd = getenv("BT_REPL_CMD") ? 1 : 0;
|
||||||
// gate -- so a steadily-walking peer dead-reckons forward frozen in the
|
if (!s_useCmd) // default: derive from replicated velocity (bodyTargetSpeed is 0 -- master walks thr=0)
|
||||||
// standing pose (legState 0, legFrm pinned) until the master happens to
|
{
|
||||||
// accelerate past standSpeed. When the peer is clearly moving forward,
|
const Vector3D &wv = updateVelocity.linearMotion;
|
||||||
// floor the demand just past standSpeed so it enters the walk cycle at
|
float spd = sqrtf((float)(wv.x * wv.x + wv.z * wv.z));
|
||||||
// once; the walk case (6/7) clamps legCycleSpeed back to walkStrideLength,
|
UnitVector zAxR;
|
||||||
// so the CADENCE still matches the actual travel (no foot-slip). Reverse
|
localToWorld.GetFromAxis(Z_Axis, &zAxR);
|
||||||
// needs no floor -- its entry gate is `commandedSpeed < ZeroSpeed`, which
|
const float fdot = -((float)wv.x * (float)zAxR.x
|
||||||
// any negative demand already trips.
|
+ (float)wv.z * (float)zAxR.z); // mech faces -Z
|
||||||
// (CORRECTED threshold: walkStrideLength is a STRIDE metric ~22, NOT
|
Scalar sd = (fdot < 0.0f) ? -spd : spd;
|
||||||
// the walk velocity ~6.1 -- gate on standSpeed, the actual gate value.)
|
if (sd > standSpeed * 0.5f && sd < standSpeed * 1.05f)
|
||||||
if (sd > standSpeed * 0.5f && sd < standSpeed * 1.05f)
|
sd = standSpeed * 1.05f;
|
||||||
sd = standSpeed * 1.05f;
|
replMppr->speedDemand = sd;
|
||||||
replMppr->speedDemand = sd;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
replMppr->speedDemand = bodyTargetSpeed;
|
||||||
|
}
|
||||||
// REPLICANT TURN-STEP (user-reported: a turning peer
|
// REPLICANT TURN-STEP (user-reported: a turning peer
|
||||||
// statue-rotates while the local mech steps): the leg SM's
|
// statue-rotates while the local mech steps): the leg SM's
|
||||||
// Standing case arms the turn-in-place "trn" clip (state 4,
|
// Standing case arms the turn-in-place "trn" clip (state 4,
|
||||||
@@ -2008,6 +2050,35 @@ void
|
|||||||
legCycleSpeed = 0.0f;
|
legCycleSpeed = 0.0f;
|
||||||
(void)AdvanceLegAnimation(dt); // joints only; travel = DeadReckon
|
(void)AdvanceLegAnimation(dt); // joints only; travel = DeadReckon
|
||||||
|
|
||||||
|
// Cadence-vs-travel sync probe (0.25s, ~4 flush/s -- cheap). Compares
|
||||||
|
// the leg CADENCE input (bodyTargetSpeed / legCycleSpeed) against the
|
||||||
|
// ACTUAL dead-reckoned ground speed; if the legs are in sync the two
|
||||||
|
// track together and legFrm advances monotonically.
|
||||||
|
if (getenv("BT_ANIM"))
|
||||||
|
{
|
||||||
|
static bool s_ainit = false;
|
||||||
|
static Point3D s_aprev;
|
||||||
|
static float s_aacc = 0.0f, s_apath = 0.0f;
|
||||||
|
if (s_ainit)
|
||||||
|
{
|
||||||
|
const float dx = (float)(localOrigin.linearPosition.x - s_aprev.x);
|
||||||
|
const float dz = (float)(localOrigin.linearPosition.z - s_aprev.z);
|
||||||
|
s_apath += sqrtf(dx * dx + dz * dz);
|
||||||
|
}
|
||||||
|
s_aprev = localOrigin.linearPosition; s_ainit = true;
|
||||||
|
s_aacc += dt;
|
||||||
|
if (s_aacc >= 0.25f)
|
||||||
|
{
|
||||||
|
DEBUG_STREAM << "[anim] cmd=" << bodyTargetSpeed
|
||||||
|
<< " drSpeed=" << (s_apath / s_aacc)
|
||||||
|
<< " legCyc=" << legCycleSpeed
|
||||||
|
<< " legState=" << (int)legStateAlarm.GetLevel()
|
||||||
|
<< " legFrm=" << legAnimation.currentFrame
|
||||||
|
<< "\n" << std::flush;
|
||||||
|
s_aacc = 0.0f; s_apath = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (getenv("BT_REPL_TRN"))
|
if (getenv("BT_REPL_TRN"))
|
||||||
{
|
{
|
||||||
static float s_rt = 0.0f; s_rt += dt;
|
static float s_rt = 0.0f; s_rt += dt;
|
||||||
@@ -3432,10 +3503,24 @@ void
|
|||||||
(Scalar)(updateVelocity.linearMotion.x * updateVelocity.linearMotion.x
|
(Scalar)(updateVelocity.linearMotion.x * updateVelocity.linearMotion.x
|
||||||
+ updateVelocity.linearMotion.z * updateVelocity.linearMotion.z);
|
+ updateVelocity.linearMotion.z * updateVelocity.linearMotion.z);
|
||||||
const Logical cameToRest = (liveSpdSq < 0.01f && sentSpdSq > 0.01f);
|
const Logical cameToRest = (liveSpdSq < 0.01f && sentSpdSq > 0.01f);
|
||||||
|
// DENSE MOTION SEND (replicant-smoothness): the position deadband
|
||||||
|
// fires IRREGULARLY (only after ~0.55u of drift), but the replicant's
|
||||||
|
// dead-reckoner predicts the next record one PAST-interval ahead and
|
||||||
|
// lerps its localOrigin toward that fixed horizon target -- so when the
|
||||||
|
// deadband cadence != the predicted cadence, the peer decelerates
|
||||||
|
// toward a stale target then lurches when a record finally lands
|
||||||
|
// (measured: dead-reckoned ground speed surging 5<->27 while the master
|
||||||
|
// walks a steady 6.13). Sending a pose record EVERY frame while moving
|
||||||
|
// makes the cadence regular + dense (records ~1 frame apart), so the
|
||||||
|
// horizon prediction matches and the lerp tracks smoothly. On a LAN
|
||||||
|
// this is a handful of small packets/frame -- negligible.
|
||||||
|
static const int s_denseTx = getenv("BT_NO_DENSE_TX") ? 0 : 1;
|
||||||
|
const Logical moving = (liveSpdSq > 0.25f);
|
||||||
if (
|
if (
|
||||||
error.LengthSquared() > posDb
|
error.LengthSquared() > posDb
|
||||||
|| lastPerformance - lastUpdate > 2.0f
|
|| lastPerformance - lastUpdate > 2.0f
|
||||||
|| cameToRest
|
|| cameToRest
|
||||||
|
|| (s_denseTx && moving)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ForceUpdate(); // type 0: pose record
|
ForceUpdate(); // type 0: pose record
|
||||||
|
|||||||
Reference in New Issue
Block a user