From bc59e39f4150135b702bcac889cd62a8cd551392 Mon Sep 17 00:00:00 2001 From: Cyd Date: Sun, 19 Jul 2026 20:53:54 -0500 Subject: [PATCH] Mech milestone: reconstruct SequenceController (helper 2/3), struct+Init verified The BT keyframe-animation player embedded in the Mech as legAnimation/ bodyAnimation. Struct field layout (from BT411's binary-offset map), default ctor, dtor, and Init(Mech*) reconstructed and compile-verified; Init is ctor-time (Mech ctor calls legAnimation.Init(this)/bodyAnimation.Init(this)) so it's real (binds owner + caches owner->GetJointSubsystem()). The per-frame gait engine (SelectSequence/Advance/Reset) is staged with Fail bodies -- it fires only once the mech is ticking, past the current ctor frontier. BT stage 23 ok; full tree still links clean. Evidence + real/staged split in SEQCTL.NOTES.md. Co-Authored-By: Claude Fable 5 --- restoration/source410/BT/SEQCTL.CPP | 97 ++++++++++++++++++++++++ restoration/source410/BT/SEQCTL.HPP | 86 +++++++++++++++++++++ restoration/source410/BT/SEQCTL.NOTES.md | 41 ++++++++++ 3 files changed, 224 insertions(+) create mode 100644 restoration/source410/BT/SEQCTL.CPP create mode 100644 restoration/source410/BT/SEQCTL.HPP create mode 100644 restoration/source410/BT/SEQCTL.NOTES.md diff --git a/restoration/source410/BT/SEQCTL.CPP b/restoration/source410/BT/SEQCTL.CPP new file mode 100644 index 00000000..e654e98a --- /dev/null +++ b/restoration/source410/BT/SEQCTL.CPP @@ -0,0 +1,97 @@ +//===========================================================================// +// File: seqctl.cpp // +// Project: BattleTech Brick: Mech animation // +// Contents: The Mech keyframe-animation player (leg / body gait clips) // +//---------------------------------------------------------------------------// +// Copyright (C) 1995, Virtual World Entertainment, Inc. // +// All Rights reserved worldwide // +// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // +//===========================================================================// + +#include +#pragma hdrstop + +#if !defined(SEQCTL_HPP) +# include +#endif + +#if !defined(MECH_HPP) +# include +#endif + +// +//############################################################################# +//############################################################################# +// +SequenceController::SequenceController() +{ + keyframeCount = 0; + jointCount = 0; + footStepThreshold = NULL; + jointIndices = NULL; + keyframeTimes = NULL; + keyframeBase = NULL; + keyframeCursor = NULL; + keyframeData = NULL; + currentFrame = 0; + currentTime = 0.0f; + jointSubsystem = NULL; + owner = NULL; + clipResource = NULL; + finishedCallback = NULL; + callbackArg2 = 0; + callbackArg3 = 0; +} + +// +//############################################################################# +// Init Bind the player to its owning mech and cache the joint subsystem the +// gait writes through. Called from the Mech ctor for legAnimation/bodyAnimation. +//############################################################################# +// +void + SequenceController::Init(Mech *owner_mech) +{ + Check(owner_mech); + owner = owner_mech; + jointSubsystem = owner_mech->GetJointSubsystem(); + clipResource = NULL; +} + +// +//############################################################################# +//############################################################################# +// +SequenceController::~SequenceController() +{ + // + // Releases the locked clip resource when reconstructed; nothing is locked + // while SelectSequence is staged. + // +} + +// +//############################################################################# +// Playback -- the per-frame gait engine (clip parse, keyframe interpolation, +// joint writes). Exercised only once the mech is ticking; not yet +// reconstructed. See SEQCTL.NOTES.md. +//############################################################################# +// +void + SequenceController::SelectSequence(int, void *, unsigned, unsigned) +{ + Fail("SequenceController::SelectSequence -- seqctl.cpp not yet reconstructed"); +} + +Scalar + SequenceController::Advance(Scalar, int) +{ + Fail("SequenceController::Advance -- seqctl.cpp not yet reconstructed"); + return 0.0f; +} + +void + SequenceController::Reset(int) +{ + Fail("SequenceController::Reset -- seqctl.cpp not yet reconstructed"); +} diff --git a/restoration/source410/BT/SEQCTL.HPP b/restoration/source410/BT/SEQCTL.HPP new file mode 100644 index 00000000..13414a43 --- /dev/null +++ b/restoration/source410/BT/SEQCTL.HPP @@ -0,0 +1,86 @@ +#if !defined(SEQCTL_HPP) +# define SEQCTL_HPP + +//##################### Forward Class Declarations ####################### + class Mech; + class JointSubsystem; + + //########################################################################## + //###################### SequenceController ########################## + //########################################################################## + // + // The BT keyframe-animation player embedded in the Mech as legAnimation and + // bodyAnimation. It plays a gait clip: walks the clip's keyframes, + // interpolates each animated joint's rotation, writes it through the joint + // subsystem, and returns the root-translation distance advanced this step. + // + // Reconstructed from the shipped binary (ctor/Init @00427768, SelectSequence + // @004277a8, Advance @0042790c, Reset @004283b8). Not in the surviving 4.10 + // archive nor the RP engine. See SEQCTL.NOTES.md. + // + class SequenceController + { + public: + // + // One root-translation entry (per keyframe); ".stride" is the forward + // (local Z) distance the gait reads. + // + struct Keyframe + { + Scalar x, y, stride; + }; + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Construction / Destruction + // + public: + SequenceController(); + ~SequenceController(); + + void + Init(Mech *owner_mech); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Playback + // + public: + void + SelectSequence( + int clip_id, + void *finished_callback, + unsigned callback_arg2, + unsigned callback_arg3 + ); + Scalar + Advance(Scalar time_slice, int move_joints); + void + Reset(int loop); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Clip data (parsed by SelectSequence; keyframe accessors read by the gait) + // + public: + int keyframeCount; + int jointCount; + Scalar *footStepThreshold; + int *jointIndices; + Scalar *keyframeTimes; + void *keyframeBase; + void *keyframeCursor; + Keyframe *keyframeData; + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Runtime state / links + // + public: + int currentFrame; + Scalar currentTime; + JointSubsystem *jointSubsystem; + Mech *owner; + void *clipResource; + void *finishedCallback; + unsigned callbackArg2; + unsigned callbackArg3; + }; + +#endif diff --git a/restoration/source410/BT/SEQCTL.NOTES.md b/restoration/source410/BT/SEQCTL.NOTES.md new file mode 100644 index 00000000..57132928 --- /dev/null +++ b/restoration/source410/BT/SEQCTL.NOTES.md @@ -0,0 +1,41 @@ +# SEQCTL.HPP / .CPP — reconstruction notes + +**Status: struct + ctor/dtor + Init RECONSTRUCTED (compile-verified); the +per-frame playback methods (SelectSequence / Advance / Reset) staged. Helper +2/3 of the Mech embedded helpers ([[MECH-LAYOUT]] step 1).** + +`SequenceController` — the BT keyframe-animation player embedded in the Mech as +`legAnimation` (@0x65c) and `bodyAnimation` (@0x6bc). Plays a gait clip: walks +keyframes, interpolates each animated joint's rotation, writes it through the +joint subsystem, returns the root-translation distance advanced. Absent from the +4.10 archive and the RP engine; reconstructed from the shipped binary + BT411's +seqctl.cpp decomp. + +## What's real vs staged + +- **Real (ctor-time):** default ctor (zeroes all fields) and `Init(Mech*)` — the + Mech ctor calls `legAnimation.Init(this)` / `bodyAnimation.Init(this)` + (binary; BT411 mech.cpp:685-686), so Init must run at construction. Init binds + `owner` and caches `jointSubsystem = owner->GetJointSubsystem()` + (JMOVER.HPP:104, returns `JointSubsystem*`), `clipResource = NULL`. +- **Staged (per-frame, after boot):** `SelectSequence` (@004277a8, clip parse + + resource lock), `Advance` (@0042790c, keyframe interpolation + joint writes — + the gait engine, ~145 lines in the decomp), `Reset` (@004283b8). These fire + only once the mech is ticking, well past the current ctor frontier, so they + Fail loudly until reconstructed. + +## Field layout + +Field set + order from BT411's binary-offset map (keyframeCount +0x14 … +callbackArg3 +0x50). Byte-exact offsets are not required for the functional +build (only wire/update-record layout needs that, and SequenceController is not +serialised) — the members are declared as named fields and BC4.52 lays them out; +the Mech's legAnimation/bodyAnimation slots size to `sizeof(SequenceController)` +self-consistently. + +## Placement + +1995 filename unknown (decomp-only; BT411 used seqctl.cpp). Filed as +BT/SEQCTL.HPP + SEQCTL.CPP. Not in the authentic BT.MAK member list, so the +build appends seqctl.obj to bt.lib via the extra-objs fallback (order is +immaterial — no static init).