Commit Graph
6 Commits
Author SHA1 Message Date
CydandClaude Fable 5 07eb74d1f7 BT410 5.3.80: joint articulation is live -- 22 nodes, and the twist reaches the board
RecurseSKLFile now builds a joint renderable for any node whose page name
resolves to a live skeleton Joint: HingeX/Y/Z -> HingeRenderable (watching
Joint::GetHinge), Ball -> BallJointRenderable (watching GetEulerAngles),
otherwise the static path.  Each holds the rest offset in one DCS and the live
rotation in a child DCS, and its Execute diffs the watched value and calls
DPL_FLUSH_DCS -- the engine's own mechanism (L4VIDRND.CPP:1026+).  The value
comes from the mech's JointSubsystem via ResolveJoint, so sim and renderer
read one source.  Gated on BT_JOINTS while it proves out.

  [skl] video\max.skl -> 26 nodes, 1 objects, 1 eye, 22 articulated

The bridge reported anim_abs=1 joints=0 twist=+0.00 before; it now reports
joints=1 twist=-0.86, matching the game's [torso] twist=-0.856.  With the mech
stationary, frames that differed by 0.0% now differ by 62-80%.

A crash it exposed: Mech::ResolveJoint passed segment->GetJointIndex()
straight to GetJoint unchecked, and a segment with no joint reports -1 --
GetNthImplementation then indexes [base + -1*4] and dies (guest 00426A1D).
Torso never hit it because it only asks for its own authored joint name; the
walk asks for every page.  Now bounds-checked against GetJointCount.

Open: the canopy does not stay rigid in the view, though it and the eye hang
off the same articulated node.  Cancelling the bridge's cage compensation
(CAGE_TWIST_SIGN=0) did not close it.  Leading hypothesis: SetupCull builds
worldToEyeMatrix from GetSegmentToWorld(siteeyepoint) -- the SIMULATION's
segment transform -- independent of the render tree, so the canopy follows our
render chain and the eye follows the sim's, and they diverge whenever one
carries the twist and the other does not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 20:46:18 -05:00
CydandClaude Fable 5 d4f105f42d BT410 5.3.69: the cockpit eye sits in the canopy -- site handling in the walk
RecurseSKLFile now walks "site=" children.  Sites get no draw component --
which is why the walk's 26 nodes matched the real capture all along: sites
were never DCS nodes -- and siteeyepoint spawns the cockpit camera with the
donor's exact construction (bt411 btl4vid.cpp:462, decomp FUN_004579a8):
offset = the site's own local rest transform, parent = the site's PARENT
joint's DCS, not the hull root.  World orientation, torso twist and gait all
arrive through chain composition.  The root-DCS eye remains only as the
zero-construction fallback for skeletons with no siteeyepoint.

Measured on the live pod with the RIO streaming: [eye] cockpit eye on
'jointeye', 26 nodes / 19 objects / 1 eye, and the bridge camera sits at
Y = hull + 7.7 -- the exact chain sum jointlocal 5.29 + hip 0.37 + torso 0.31
+ jointeye 1.69.  canopy_eye1.png is the pilot's view, the mech's own nose
wedge visible below the sightline.  Own-mech cage handling is the next layer.

Also: eye_count threading through ReadSKLFile/RecurseSKLFile, and the [skl]
summary now reports it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 15:18:27 -05:00
CydandClaude Fable 5 d143f833ab BT410 5.3.64: THE COCKPIT EYE IS LIVE -- root+eye composition, and the emulator
deadlock it exposed

The camera gap root-caused and fixed through three layers:

LAYER 1 (ours): "chain the engine after the skeleton" was a non-fix.  The
engine's MakeEntityRenderables only accepts Object/Rubble resources, so
chaining it with a Skeleton printed "wrong video resource type" and built
NOTHING -- the fifodump proved it: zero vr_flush_dcs_artic records.  The real
fix mirrors the engine's Mover composition (L4VIDEO.CPP:4795-4860) inside our
mech case: a Dynamic RootRenderable (whose ctor seeds its DCS from
localToWorld and whose Execute re-flushes on change -- the ONLY source of
per-frame wire articulation), the skeleton hung UNDER its DCS via ReadSKLFile's
new parent_dcs parameter, and for the inside view a DPLEyeRenderable on that
root with the published EyepointRotation.  Also explains the mystery monolith
in the first frame: the skeleton was parked at the world origin with the
camera inside its shins.

LAYER 2 (1995 library, read from our own linked symbols): dpl_DrawSceneComplete
= velocirender_frameack(0), and frameack's unsolicited-reply path prints
"dpl error - unsolicited input during frame ack", adds the 1995 authors' own
puzzled "flush artic??" when the stray action is 0x1f, and calls exit(9).
Documented before it ever fires.

LAYER 3 (emulator, the actual deadlock): with per-frame articulation flowing
for the first time, the game stopped drawing at frame 232 -- one 0x1f burst
per frame forever, no receives, no error.  The VPX device feeds the frame ack
only after 6 CONSECUTIVE empty polls and reset that counter on EVERY
outputData write; per-frame articulation writes made the count unreachable, so
dpl_DrawSceneComplete never went true.  Fix: the reset is gated on
!frame_outstanding -- once a draw is outstanding the only receive the game
will do next is the frame ack.  The iserver-drain concern the reset guarded is
boot-time only, when no frame is outstanding.

Verified: two agreeing runs of ours on the fixed emulator (611 draws / 222
artic batches in run 2 -- the 232 wall is gone), camera travelling with the
mech (cam -329.7,0,60.5 -> -362.3,0,54.5 across 8s), anim_abs 0 -> 1 on the
bridge, view now INSIDE the cockpit cage.  Shipped binary re-run on the fixed
emulator: launches and runs, no regression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 09:46:23 -05:00
CydandClaude Fable 5 d66c2b0812 BT410 5.3.55: the mech skeleton is built -- .SKL walked into a dpl_DCS tree
BTL4VideoRenderer answers MechClassID: walks the video-object chain the way
the engine does, hands every L4VideoObject::Skeleton entry to ReadSKLFile, and
recurses the .SKL into a dpl_DCS tree with geometry instanced onto it.

Verified repeatedly on the live pod: '[skl] video\mad.skl -> 26 nodes, 19
objects', with no 'wrong video resource type' complaint and no load failures.
Those counts are exactly what the file declares (25 joint= entries + root, 19
Object= entries).

Corrects the earlier success criterion in this file, which said 22 instances
by reading the reference capture's 'instance x22' against DZoneCount=22.
Damage zones are not geometry -- 28 dzone= tags spread across 19 objects.

Translations are written to matrix[3]/[7]/[11], MUNGA's own AffineMatrix
layout.  It walks cleanly but no frame has been seen WITH the mech yet, so
the slot choice is recorded as unconfirmed.  Rotation stays identity by
design: every base-pose angle in MAD.SKL is 0 or ~1e-3, so translation alone
assembles the model and isolates one convention at a time.

AND A CORRECTION I have to flag loudly: I earlier concluded from single runs
that non-identity translations crashed the pod, 'isolated' it, and 'confirmed'
the alternative also crashed.  That was all noise.  The same binary re-run
gives walk / crash / walk / crash -- the known intermittent plane-write defect
is now firing on ~half of pod runs and lands at different points each time,
which is precisely what made it look deterministic.  Never accept a single
pod run as evidence on this rig; require two agreeing runs.

That defect is now the top of the list: a run must survive both the skeleton
build and the launch to render anything, which at ~50% is a coin flip on a
four-minute cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 18:46:37 -05:00
CydandClaude Fable 5 ed7843b89f BT410 5.3.49: first renderable answer -- BTPlayer, and the pod stops complaining
BTL4VideoRenderer now overrides MakeEntityRenderables.  Class 3035 resolves
to BTPlayerClassID (the BT enum block starts at 3000 in VDATA.HPP), and a
player carries no graphics -- exactly what the engine already does for its
own PlayerClassID with an empty case.  Everything else chains to DPLRenderer,
so the override can only add answers.

On the pod: the 'couldn't figure out how to MakeEntityRenderables' complaint
is gone and the run no longer exits, it keeps running.  It still renders
nothing -- the wire fifodump grows at ~24 bytes/sec, keep-alive rather than a
frame stream -- which is expected, since only the player has been answered
and the mech and arena still have no renderables.

Banked a practical problem worth fixing before the next session: a pod run
that does NOT crash produces no readable log, because the conf redirects the
game's stdout and DOS buffers it.  Every readable log this session came from
a run that crashed and had its buffer flushed by the fault handler.  The
RC.TXT marker (a separate command) survives that, and the com3/serial3=file
trick from the emulator notes would give live unbuffered output -- worth
wiring in, otherwise progress is invisible precisely when things are going
well.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 08:34:44 -05:00
CydandClaude Fable 5 d9b34ddc63 source410: THE WHOLE 4.10 TREE COMPILES - 11/11 under the fleet's BC++ 4.52
All 10 surviving original TUs plus the reconstructed BTL4APP.CPP pilot build
clean with the authentic OPT.MAK flags (compile410.sh --sweep). First time
the 4.10 BattleTech source has compiled since 1996.

- layout_probe.cpp: the period compiler measures 1995 layouts from the
  surviving headers; validated 3/3 against binary alloc sizes (BTMission
  0xFC, BTL4ModeManager 0xC, BTRegistry 0x10). Base boundary: Simulation
  0xD0 / Entity 0x1C4 / Mover 0x300 / JointedMover 0x328 => Mech-own region
  0x328-0x854 (MECH-LAYOUT.md staging worksheet).
- 13 staged headers close the family ([T3] reserved[]-parked layouts;
  interfaces PROVEN by the surviving consumers): MECH, MECHSUB, HEAT,
  POWERSUB, MECHWEAP, EMITTER, MECHMPPR, BTPLAYER (BTPlayer__MakeMessage =
  Player's 8 args + roleName/teamName [T1 via BTREG]), PROJTILE, MISSILE,
  BTL4MPPR, BTL4VID + the round-2 BTCNSL/BTSCNRL.
- compile410.sh: PCH gate retired (bt.hpp/mungal4.hpp full include sets),
  DPL SDK roots on the include line.
- BTL4APP.CPP: appmgr include + GetApplicationManager()->GetFrameRate() +
  ResourceDescription:: scoping; Fail() held at its recorded line 400.
- Evidence ledgers: STAGED-HEADERS.NOTES.md, MECH-LAYOUT.md, BACKFILLS,
  BTCNSL (binary-recovered console wire IDs), BTSCNRL.

Remaining for a linkable BTL4OPT: the ~40 missing TU bodies (917-function
manifest) - the header skeleton they grow into now exists and compiles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 07:58:26 -05:00