Camera seat LIVE + Mech::PlayerLinkMessageHandler reconstructed (@0049f624)

The spectator/broadcast seat works end-to-end: a hostType=1 +
vehicle=camera pilot page boots a CameraShip whose 62-camera arena1
network loads from the BTL4.RES type-27 resource (the engine's
CreateStreamedCameraInstances existed all along -- the file probe falls
back to it), the BTCameraDirector locks onto the first live mech, and
the ship TRACKS it (sees=1, goal advancing) and CUTS between authored
camera positions (screenshot-verified: wide arena shot -> close
tracking shot).

The missing piece was the Mech override of PlayerLinkMessageHandler
(@0049f624), which the reconstruction never filled.  The engine base
resolves mech->player; BT's override adds:
  1. the REVERSE link player->playerVehicle = this on EVERY node
     (replicants included) -- how the camera director and scoreboard
     find a REMOTE player's mech; without it a spectator parks forever
     ('NO goal entity')
  2. clears NonScoringPlayerFlag (0x4000 = bit 14): a pilot with a
     vehicle is a SCORING player -- this admits REPLICATED players to
     the ranking pass, so cross-node rank/score displays work
  3. master only: seeds the heat bank's ambientTemperature (bank
     @0x1d4) from the mission [mission] temperature= (BTMission+0xf4)
     -- correcting the heat family's 'frozen 300' deviation note (it
     was never frozen; THIS is the writer)

Bridge BTSetBankAmbientTemperature lives in heatfamily_reslice.cpp
(mech.cpp cannot include subsystem headers -- local-stub collision).
BT_CAM_LOG diagnostics: camera-network count, director pick + Players
group census, ship follow state, link dispatch/receive.

Verified live: 2-seat (mech + camera) relay session -- replicated
player shows +veh, director goal locked w/ 30s timer, ship tracking a
moving mech through camera cuts; standard 2-node mech smoke PASS
(un-regressed).  Lesson re-learned: a 'clean' build filtered on 'error
C' missed a linker file-lock failure -- one whole test cycle ran
against a stale exe (the /FORCE gotcha's cousin; grep -i error, not
error C).

Remaining (task open): ranking-window overlay draw (L4VIDRND stubs),
operator-app camera-seat row, shot polish.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-18 16:10:29 -05:00
co-authored by Claude Fable 5
parent 74d9d3b6ff
commit 4459262b9c
9 changed files with 469 additions and 5 deletions
+10
View File
@@ -580,6 +580,16 @@ void
camera_stream.AdvancePointer(model->instanceSize);
}
res->Unlock();
// BT port diag (BT_CAM_LOG): the camera-seat bring-up needs to know the
// network actually loaded (type-27 res, all 8 maps ship in BTL4.RES)
if (getenv("BT_CAM_LOG"))
{
int n = 0;
SChainIteratorOf<CameraInstance*> it(cameraList);
while (it.ReadAndNext() != NULL) ++n;
DEBUG_STREAM << "[cam] streamed camera network '" << map_name
<< "': " << n << " camera(s) loaded\n" << std::flush;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+19
View File
@@ -314,11 +314,30 @@ void
//
if (!goalEntity)
{
// BT port diag (BT_CAM_LOG, 1 Hz): parked with no goal
if (getenv("BT_CAM_LOG"))
{
static float s_ng = 0.0f; s_ng += time_slice;
if (s_ng >= 1.0f) { s_ng = 0.0f;
DEBUG_STREAM << "[cam] ship: NO goal entity (parked)\n"
<< std::flush; }
}
return;
}
Check(goalEntity);
Point3D target;
target.Multiply(focusOffset, goalEntity->localToWorld);
// BT port diag (BT_CAM_LOG, 1 Hz): live follow state
if (getenv("BT_CAM_LOG"))
{
static float s_fg = 0.0f; s_fg += time_slice;
if (s_fg >= 1.0f) { s_fg = 0.0f;
DEBUG_STREAM << "[cam] ship: goal at (" << target.x << ","
<< target.z << ") cam=" << (void*)currentCamera
<< " sees=" << (currentCamera
? (int)currentCamera->CanCameraSee(target) : -1)
<< "\n" << std::flush; }
}
//
//------------------------------------------------------------------------