Correct big-endian offboard state flag checks

This commit is contained in:
chazmm committed 2026-09-06 22:36:00 +01:00
1 parent 0a3904cd00
commit 0b579e51e3
5 files changed
+36 -5

No files matched your search

+3 -2
View File
@@ -20,7 +20,8 @@ impl StateSelector {
if p.has_2476(0x8000) {
return PhysicalStateId::BipedGround;
}
if p.has_2476(0x80) && !p.has_2484(1) {
//Native lbz2484 selects the high byte of the big-endian flag word.
if p.has_2476(0x80) && !p.has_2484(0x100_0000) {
return PhysicalStateId::BipedAir;
}
if facts.force_known_air {
@@ -72,7 +73,7 @@ impl StateSelector {
{
return PhysicalStateId::WipeoutGround;
}
if p.has_2476(0x80) && !p.has_2484(1) {
if p.has_2476(0x80) && !p.has_2484(0x100_0000) {
return PhysicalStateId::BipedAir;
}
if p.has_2476(0x8000) {
@@ -35,7 +35,10 @@ impl StateSelector {
return PhysicalStateId::WipeoutGround;
}
if !p.has_2480(0x10) {
if p.has_2484(1) {
//82D8ADE8's BipedAir branch reads lhz2484, then tests its low bit. On
//big-endian Xenon this is full-word bit16 (Offboard328),
//not bit0 (the unrelated BipedBoardOnGround attribute).
if p.has_2484(0x1_0000) {
if p.has_2476(0x8000) || p.has_2476(0x80) {
current
} else {
@@ -1,10 +1,11 @@
//! Bounded numeric history for user-reproduced airborne bails. No per-frame IO.
//! Bounded numeric history for user-reproduced off-board bails. No per-frame IO.
use crate::physics::SkaterRuntime;
use std::collections::VecDeque;
#[derive(Debug)]
#[allow(dead_code)] // Fields are serialized together only when a bail is requested.
struct Sample {
physical_state: u32,
tick: i32,
flags: [u32; 3],
packet: skate_core::player::offboard::air_prediction::Packet,
@@ -37,6 +38,7 @@ pub(crate) fn record(skater: &mut SkaterRuntime) {
let p = &skater.player_input.processed;
if history.samples.len() == 32 { history.samples.pop_front(); }
history.samples.push_back(Sample {
physical_state: p.state_2508,
tick: state.tick,
flags: [p.flags_2476, p.flags_2480, p.flags_2484],
packet: state.packet,
@@ -51,7 +53,7 @@ pub(crate) fn record(skater: &mut SkaterRuntime) {
if skater.wipeout.state.reasons.iter().any(|&requested| requested) {
// Format in memory, then one write; never send Debug's individual
// formatting fragments to the Windows redirected stderr handle.
let report = format!("SKATE_BIPED_AIR_BAIL history={:#?}", history.samples);
let report = format!("SKATE_BIPED_BAIL history={:#?}", history.samples);
eprintln!("{report}");
history.samples.clear();
history.reports += 1;
+1
View File
@@ -151,6 +151,7 @@ pub(super) fn check_after_physics(
ground_kind_356: skater.offboard.retained_contact.kind_164,
},
);
super::offboard::air_diagnostics::record(skater);
Ok(())
}
PhysicalStateId::PhysicsAir => skater.wipeout.check_air(&observations, false),
+24
View File
@@ -0,0 +1,24 @@
# Off-board state flag correction
The user reported jumps immediately playing a landing animation, repeated
landing animations and rising motion after walking off a ledge. The preceding
run's stderr contained no airborne bail report; this alone does not establish
whether the airborne state was entered.
Static evidence: TU3 dump `default_82000000_011B0000.bin`, SHA-256
`f4aa113eb541bfba03dbc108cf5ab43f58c965b20fa3b82f9c40938a0ad841c4`.
The generated instruction listing for `82D8ADE8` contains:
- `82D8B8D4`: `lhz r11,2484(r4)`, followed by a low-bit test.
- `82D8B490` and `82D8B5F0`: `lbz r11,2484(r4)`, followed by a low-bit test.
On this big-endian target these test full-word masks `0x00010000` and
`0x01000000`, respectively. The port incorrectly used `0x00000001` for all
three. Bit16 is published from Offboard328, the airborne continuation flag;
bit0 is a separate animation attribute. BipedAir therefore incorrectly returned
to BipedGround while its airborne flag was still set.
Corrected all three masks. Repeated premature ground entry is a plausible
cause of the reported animation loop; gameplay confirmation remains with the
user. Build only, no tests run. Bounded bail diagnostics also cover BipedGround
so any remaining turning-related failure can be captured.