MP task #48 (partial): -net aim+drive already work; localize the real gap

Re-measured interactive -net combat on a 2-node run. The KB's "aim ray dead /
drive dead in -net" was STALE: A's aim ray is live (noRay=0, the active eye
publishes the aim camera) and A drives (BT_AUTODRIVE/BT_GOTO move it). The real
blocker to a human cross-pod kill via the beam path is NOT the netcode:

- Boresight inherits the mech BODY pitch. The aim ray = the active eye's view
  dir; on sloped terrain the body pitches to conform and the boresight points
  ~8 deg down ([EYE] up=(-.03,.99,-.14) == [pick] ldir.y=-0.145 every frame),
  so at range the ray hits terrain ~50-100m short of the enemy (mechPicks=0).
- Drive/goto stalls ~700m short before closing to pick/weapon range.
- PickRayHit vs a replicant is thus unconfirmed, but the replicant localToWorld
  IS correct (lstart magnitude == true A->B distance; the DeadReckon +
  localToWorld=localOrigin block already tracks the replicated position).

Change: add a gated BT_GOTO="enemy" test mode (beeline toward the nearest live
replicant) -- MP spawn coords vary per run so a fixed "x z" can't reliably face
the peer. KB (multiplayer.md) updated with the corrected findings + the real
remaining work (torso-pitch/level-boresight aim ray + drive-to-range).

Solo un-regressed; btl4.exe builds; KB validator clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 13:13:41 -05:00
co-authored by Claude Fable 5
parent 54b6663b4d
commit bac45851ad
2 changed files with 48 additions and 6 deletions
+23 -4
View File
@@ -104,11 +104,30 @@ off in solo. `[mp-hdlr]` (BT_MP_NET, mech.cpp:554) logs each applied cross-pod h
`scratchpad/mp_test.sh`: A `-egg MP.EGG -net 1501`, B `-net 1601`, then `python tools/btconsole.py MP.EGG
127.0.0.1:1501 127.0.0.1:1601` (MP.EGG `[pilots]` = game ports 1502/1602).
## Interactive -net aim + drive (task #48, 2026-07-09) — partial; the blocker is NOT the netcode [T2]
Re-measured on a 2-node one-box run (A `BT_AUTODRIVE`/`BT_GOTO`, `BT_AIM_LOG`, `BT_MP_LOG`). **The prior
"aim ray dead / drive dead in -net" claim was STALE — both work now:** A's aim ray is live (`noRay=0`, the
active eye publishes the aim camera), and A DRIVES (`BT_AUTODRIVE`/`BT_GOTO` move it). What actually blocks
a HUMAN cross-pod kill via the real beam path:
- **Boresight inherits the mech BODY pitch.** The aim ray = the active EYE's view direction (with reticle
at 0,0). On sloped terrain the mech body pitches to conform (ground model), the cockpit eye/boresight
pitches with it, and the pick ray points ~8° DOWN (`[EYE] up=(-.03,.99,-.14)` == `[pick] ldir.y≈-0.145`,
every frame). At range that ray hits terrain (`groundPicks`) ~50-100 m short of the enemy → `mechPicks=0`.
A close enemy (< ~50 m) would still resolve. Real BT aims the TORSO pitch independently of leg/body tilt;
the reconstruction ties the boresight to the render eye. Fixing = derive the aim ray from a level torso
boresight (yaw only) OR add torso pitch, not the pitched body eye.
- **Drive/goto stalls.** A repeatedly stops (`gait adv=0`) ~700-750 m from the enemy before closing to
weapon/pick range — a locomotion/goto reliability issue, not MP.
- **PickRayHit vs a replicant is UNCONFIRMED** (blocked by the two above — A never faces the enemy at close
range). `localToWorld` on the replicant IS correct (`[pick] lstart` magnitude ≈ true A→B distance; the
DeadReckon + `localToWorld=localOrigin` block at mech4.cpp:1191 tracks the replicated position).
Test aid added: `BT_GOTO="enemy"` beelines toward the nearest live replicant (spawn coords vary per run, so
a fixed "x z" can't reliably face the peer). Recipe: `scratchpad/mp_kill_test.sh`.
## Remaining (P6 phase 4 / Phase 7)
Interactive 2-window driving + the `-net`-mode aim projection / drive (A's aim ray was dead — `noRay`, and
`BT_AUTODRIVE`/`BT_GOTO` didn't move A in `-net` mode) so a HUMAN (not just the FORCE_DMG hook) can aim +
fire cross-pod; replicant GAIT animation (derive from replicated velocity); the pod-LAN config (real IPs,
bare-IP pilot entries). See [[open-questions]]. [T3]
Human-playable cross-pod aim (torso-pitch / level-boresight aim ray + drive-to-range reliability, above) so a
HUMAN not just the FORCE_DMG hook can aim + fire cross-pod; replicant GAIT animation (derive from
replicated velocity); the pod-LAN config (real IPs, bare-IP pilot entries). See [[open-questions]]. [T3]
## MP-front scout (task #45, 2026-07-09) — the P6 chain SURVIVES the combat/HUD rework [T2]
Re-ran the one-box smoke test on the current build (world-pick targeting, weapon groups, death
+25 -2
View File
@@ -1499,10 +1499,33 @@ void
if (s_goto < 0)
{
const char *gv = getenv("BT_GOTO");
if (gv && sscanf(gv, "%f %f", &s_gx, &s_gz) == 2) s_goto = 1;
if (gv && !stricmp(gv, "enemy")) s_goto = 2; // chase nearest replicant
else if (gv && sscanf(gv, "%f %f", &s_gx, &s_gz) == 2) s_goto = 1;
else s_goto = 0;
}
if (s_goto == 1)
if (s_goto == 2)
{
// DYNAMIC target (test harness): beeline toward the CLOSEST live
// peer replicant wherever it currently is -- MP spawn positions
// vary per run, so a fixed "x z" can't reliably face the enemy.
extern int BTGetTargetCandidates(Entity *shooter, Entity **out, int maxOut);
Entity *ec[32];
const int enc = BTGetTargetCandidates((Entity *)this, ec, 32);
float best = 1e30f; int found = 0;
for (int ei = 0; ei < enc; ++ei)
{
Mech *em = (Mech *)ec[ei];
if (em == 0 || em->GetInstance() != ReplicantInstance
|| em->IsMechDestroyed()) continue;
Point3D ep = em->localOrigin.linearPosition;
float edx = (float)ep.x - (float)localOrigin.linearPosition.x;
float edz = (float)ep.z - (float)localOrigin.linearPosition.z;
float ed2 = edx*edx + edz*edz;
if (ed2 < best) { best = ed2; s_gx = (float)ep.x; s_gz = (float)ep.z; found = 1; }
}
if (found) s_goto = 2; else { gBTGotoActive = 0; }
}
if (s_goto == 1 || (s_goto == 2 && (s_gx != 0.0f || s_gz != 0.0f)))
{
float ddx = s_gx - (float)localOrigin.linearPosition.x;
float ddz = s_gz - (float)localOrigin.linearPosition.z;