Rework input buffer to match HDR closer (#79)
CI / build-and-test (push) Successful in 1m24s
CI / production-build (push) Successful in 11m47s

## Summary

- Preserve distinct same-action bindings in rollback input frames.
- Add independent command lifetimes with tap and state-scoped hold buffering.
- Detect second shield bindings and consume shield commands for air dodge.
- Fix duplicate keyboard mappings being overwritten.

Reviewed-on: #79
Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #79.
This commit is contained in:
2026-10-03 09:20:56 +00:00
committed by EIREXE
parent 47f7ae1e69
commit aca3886113
11 changed files with 711 additions and 165 deletions
+30 -7
View File
@@ -1,13 +1,17 @@
use crate::{
fighter::{
FighterInvulnerabilityState, animation::AnimKind, state::{
FighterInvulnerabilityState,
animation::AnimKind,
state::{
CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext,
UpdateContext,
air::{self, AirborneStateCommon},
fall::FallState,
land::LandingType,
},
}, input, math::vec::FGVec2,
},
input,
math::vec::FGVec2,
};
#[derive(Debug, Clone, Hash)]
@@ -29,8 +33,13 @@ impl FighterStateImpl for AirDodgeState {
}
fn update(&mut self, state_context: &mut UpdateContext) {
let airdodge_intangible_end = state_context.fighter_attributes.air_dodge_intangible_start + state_context.fighter_attributes.air_dodge_intangible_duration;
if state_context.animation_frame == state_context.fighter_attributes.air_dodge_intangible_start {
let airdodge_intangible_end = state_context.fighter_attributes.air_dodge_intangible_start
+ state_context
.fighter_attributes
.air_dodge_intangible_duration;
if state_context.animation_frame
== state_context.fighter_attributes.air_dodge_intangible_start
{
*state_context.vulnerability = FighterInvulnerabilityState::Intangible;
} else if state_context.animation_frame >= airdodge_intangible_end {
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
@@ -54,6 +63,13 @@ impl FighterStateImpl for AirDodgeState {
fn on_enter(&mut self, state_context: &mut EnterContext) {
state_context.play_animation(AnimKind::AirDodge, false);
state_context
.input
.clear_command(input::FighterCommands::Shield);
state_context
.input
.clear_command(input::FighterCommands::GuardHold);
state_context.velocity.0 =
self.direction * state_context.fighter_attributes.air_dodge_velocity;
}
@@ -65,11 +81,11 @@ impl FighterStateImpl for AirDodgeState {
fn surface_policy(&self) -> super::SurfacePolicy {
super::SurfacePolicy::Airborne(crate::fighter::surface::EcbLockPolicy::StartOnDetach)
}
fn on_exit(&mut self, state_context: &mut super::ExitContext) {
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
}
fn name(&self) -> String {
Self::NAME.to_owned()
}
@@ -79,7 +95,14 @@ pub fn check_input(state_context: &InterruptContext) -> Option<FighterState> {
state_context
.input
.has_command(input::FighterCommands::Shield)
.then(|| {
.then_some(())
.or_else(|| {
state_context
.input
.has_command(input::FighterCommands::GuardHold)
.then_some(())
})
.map(|_| {
FighterState::AirDodge(AirDodgeState {
direction: state_context
.input