Input: PadRIO -- play without the pod (L4CONTROLS=PAD), Workstream A.1
Ported from RP412: RIOBase split out of the serial RIO (L4RIO.h), rioPointer is RIOBase* (L4CTRL.h), PAD token -> new PadRIO() speaking the RIO surface from an XInput pad + keyboard (L4PADRIO/L4PADBINDINGS, vRIO bindings.txt grammar, hot-plug), KeyLight RGB mirror TU (BT412KEYLIGHT, /std:c++17 per-file). BT-side fixes PadRIO forced into the open: - Both keyboard input bridges (mech4.cpp, mechmppr.cpp BT_KEY_BRIDGE) stand down when a RIO device exists -- they overwrote the engine controls push every frame. M/X conveniences stay live. - Mapper attribute chain OFF BY ONE (latent real-pod bug): the DOS chain below MechControlsMapper carried two base attributes, WinTesla carries one, and AttributeIndexSet::Find is positional -- the .CTL stick mapping wrote throttlePosition. Pad slot + binary-locked enum; gotcha ledgered (reconstruction-gotchas #11). Verified: PAD throttle lever ramps + sticks, stick turns with the authentic speed-vs-turn clamp (61.5 -> 22.0 u/s), mech drives; keyboard fallback intact (BT_FORCE_THROTTLE harness). New diags: BT_CTRLMAP_LOG, BT_STICK_LOG. (Phase 2 of docs/BT412-ROADMAP.md) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2551,6 +2551,18 @@ void
|
||||
// which runs in the subsystem-roster walk below (un-skipped under this env).
|
||||
static const int s_realControls = BTEnvOn("BT_REAL_CONTROLS", 1); // default ON (=0 to disable)
|
||||
MechControlsMapper *mppr = MappingMapper(); // roster slot 0 (task #7)
|
||||
//
|
||||
// BT412: when a RIO device exists (the pod board, or PadRIO's
|
||||
// pad/keyboard synthesizer under L4CONTROLS=PAD), the ENGINE's
|
||||
// controls push writes the mapper's published input attributes from
|
||||
// the device groups -- the WASD stand-in write below would clobber
|
||||
// it every frame. The bridge speaks for the hardware only when
|
||||
// there is none; the demand CONSUME side runs either way.
|
||||
//
|
||||
LBE4ControlsManager *bridgeControls = (application != 0)
|
||||
? (LBE4ControlsManager *)application->GetControlsManager() : 0;
|
||||
const int deviceOwnsInput =
|
||||
(bridgeControls != 0 && bridgeControls->rioPointer != 0);
|
||||
if (s_realControls && mppr != 0)
|
||||
{
|
||||
// Diagnostic: what the ENGINE controls push left in the attribute since
|
||||
@@ -2558,10 +2570,13 @@ void
|
||||
// here as pre != our previous write).
|
||||
float preThrottle = mppr->throttlePosition;
|
||||
(void)preThrottle;
|
||||
if (!deviceOwnsInput)
|
||||
{
|
||||
mppr->throttlePosition = (throttle >= 0.0f) ? throttle : -throttle;
|
||||
mppr->reverseThrust = (throttle < 0.0f) ? 1 : 0; // ControlsButton: >=1 engaged
|
||||
mppr->stickPosition.x = turn; // Basic mode: turn = stick yaw
|
||||
mppr->stickPosition.y = 0.0f;
|
||||
}
|
||||
// Consume the PREVIOUS frame's interpreted demands (the mapper ticks in
|
||||
// the roster walk after this block -- one frame of input latency).
|
||||
// turnDemand is the mode-shaped steering; speedDemand (world u/s, sign =
|
||||
@@ -2587,7 +2602,9 @@ void
|
||||
<< " turnDemand=" << mppr->turnDemand
|
||||
<< " mode=" << mppr->controlMode
|
||||
<< " mapper=" << (void*)mppr
|
||||
<< " &mode=" << (void*)&mppr->controlMode << "\n" << std::flush;
|
||||
<< " &mode=" << (void*)&mppr->controlMode
|
||||
<< " &stick=" << (void*)&mppr->stickPosition
|
||||
<< " &thr=" << (void*)&mppr->throttlePosition << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
# include <pilot.hpp>
|
||||
#endif
|
||||
#include <torso.hpp> // real Torso: analog aim axes @0x1F0/0x1F4, horizontalEnabled @0x250
|
||||
// LBE4ControlsManager (rioPointer presence gates the key bridge) -- needs
|
||||
// the btl4app/btl4mode forward-decl order btl4mppr.cpp / mech4.cpp use.
|
||||
#if !defined(BTL4APP_HPP)
|
||||
# include <btl4app.hpp>
|
||||
#endif
|
||||
#if !defined(BTL4MODE_HPP)
|
||||
# include <btl4mode.hpp>
|
||||
#endif
|
||||
#if !defined(L4CTRL_HPP)
|
||||
# include <l4ctrl.hpp>
|
||||
#endif
|
||||
#include <hud.hpp> // real HUD: freeAimSlew @0x28C
|
||||
|
||||
#define JM_CLOSE_ENOUGH 1.0e-4f // _DAT_004b027c
|
||||
@@ -252,6 +263,15 @@ MechControlsMapper::MessageHandlerSet&
|
||||
const MechControlsMapper::IndexEntry
|
||||
MechControlsMapper::AttributePointers[]=
|
||||
{
|
||||
//
|
||||
// BT412 pad slot (see the mechmppr.hpp enum note): the DOS chain below
|
||||
// the mapper carried a second base attribute the WinTesla chain lacks,
|
||||
// and Find() is positional -- this entry occupies the missing slot so
|
||||
// the stream's IDs (stick=3...) land on the right members. No stream
|
||||
// references ID 2 (verified via BT_CTRLMAP_LOG); a lookup returns NULL.
|
||||
//
|
||||
{ Subsystem::NextAttributeID, "BT412BaseSlotPad",
|
||||
(Simulation::AttributePointer)0 },
|
||||
ATTRIBUTE_ENTRY(MechControlsMapper, StickPosition, stickPosition), // 0x114
|
||||
ATTRIBUTE_ENTRY(MechControlsMapper, ThrottlePosition, throttlePosition), // 0x11C
|
||||
ATTRIBUTE_ENTRY(MechControlsMapper, PedalsPosition, pedalsPosition), // 0x120
|
||||
@@ -595,6 +615,18 @@ void
|
||||
{
|
||||
static const int s_keyBridge =
|
||||
(getenv("BT_KEY_BRIDGE") == 0 || *getenv("BT_KEY_BRIDGE") != '0');
|
||||
//
|
||||
// BT412: a live RIO device (the pod board, or PadRIO's pad/keyboard
|
||||
// synthesizer under L4CONTROLS=PAD) feeds the analog input attributes
|
||||
// through the engine controls push that just ran -- the keyboard
|
||||
// bridge's ANALOG writes below would clobber the device every frame.
|
||||
// They stand down when a device exists; the desktop conveniences
|
||||
// (M mode-cycle, X torso-recenter) stay live either way.
|
||||
//
|
||||
LBE4ControlsManager *bridge_controls = (application != 0)
|
||||
? (LBE4ControlsManager *)application->GetControlsManager() : 0;
|
||||
const int device_owns_input =
|
||||
(bridge_controls != 0 && bridge_controls->rioPointer != 0);
|
||||
if (s_keyBridge && mech != 0 && application != 0
|
||||
&& (Entity *)mech == application->GetViewpointEntity())
|
||||
{
|
||||
@@ -670,8 +702,11 @@ void
|
||||
}
|
||||
}
|
||||
}
|
||||
throttlePosition = (key_throttle >= 0.0f) ? key_throttle : -key_throttle;
|
||||
reverseThrust = (key_throttle < 0.0f) ? 1 : 0;
|
||||
if (!device_owns_input)
|
||||
{
|
||||
throttlePosition = (key_throttle >= 0.0f) ? key_throttle : -key_throttle;
|
||||
reverseThrust = (key_throttle < 0.0f) ? 1 : 0;
|
||||
}
|
||||
// CONTROL-MODE AXIS ROUTING (2026-07-13, the pod mapping): in
|
||||
// BASIC the stick steers the legs (turn) and the torso auto-
|
||||
// centers; in STANDARD/VETERAN the stick is the TORSO (free aim /
|
||||
@@ -690,13 +725,19 @@ void
|
||||
}
|
||||
if (controlMode == BasicMode)
|
||||
{
|
||||
stickPosition.x = key_turn;
|
||||
pedalsPosition = 0.0f;
|
||||
if (!device_owns_input)
|
||||
{
|
||||
stickPosition.x = key_turn;
|
||||
pedalsPosition = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stickPosition.x = gBTTwistAxis; // the torso axis
|
||||
pedalsPosition = key_turn; // A/D = the pedals
|
||||
if (!device_owns_input)
|
||||
{
|
||||
stickPosition.x = gBTTwistAxis; // the torso axis
|
||||
pedalsPosition = key_turn; // A/D = the pedals
|
||||
}
|
||||
// 'X' recenter pulse (2026-07-13): one-frame centerCommand
|
||||
// -> the sim arms recenterActive and Recenter (@004b6918)
|
||||
// slews the torso home; any Q/E input cancels it sim-side.
|
||||
@@ -712,15 +753,21 @@ void
|
||||
gBTTorsoRecenter = 0;
|
||||
rcTorso->CommandRecenter();
|
||||
}
|
||||
else
|
||||
else if (!device_owns_input)
|
||||
{
|
||||
// A live device's mapped button owns
|
||||
// centerCommand; only the keyboard
|
||||
// bridge clears it while unpressed.
|
||||
rcTorso->ClearRecenterCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stickPosition.y = 0.0f;
|
||||
if (!device_owns_input)
|
||||
{
|
||||
stickPosition.y = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,9 +130,19 @@ class Pilot;
|
||||
// table @0050efd0. (The recorded member offsets carry the engine's
|
||||
// low-bit "scalar" tag, e.g. 0x115 -> &stickPosition @0x114.)
|
||||
//
|
||||
// BT412 (databinding, 2026-07-14): the binary's stream IDs put the
|
||||
// stick at 3, i.e. the DOS chain below the mapper carried TWO base
|
||||
// attributes. The WinTesla Simulation/Subsystem chain carries ONE
|
||||
// (SimulationState, Subsystem::NextAttributeID == 2), and the engine's
|
||||
// AttributeIndexSet::Find is POSITIONAL (ID N -> slot N-1), so the
|
||||
// enum is locked to the binary (+1) and mechmppr.cpp pads the missing
|
||||
// base slot -- without it every mapper attribute resolved one entry
|
||||
// late (the .CTL stick mapping wrote throttlePosition; found the day
|
||||
// PadRIO first drove the mapper from a live device).
|
||||
//
|
||||
public:
|
||||
enum {
|
||||
StickPositionAttributeID = Subsystem::NextAttributeID, // 3
|
||||
StickPositionAttributeID = Subsystem::NextAttributeID + 1, // 3 (binary-locked)
|
||||
ThrottlePositionAttributeID, // 4
|
||||
PedalsPositionAttributeID, // 5
|
||||
ReverseThrustAttributeID, // 6
|
||||
|
||||
Reference in New Issue
Block a user