Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
021f466ac3 | ||
|
|
97788b7df8 | ||
|
|
32428982ad | ||
|
|
47f7ae1e69 |
+5
-2
@@ -7,9 +7,10 @@ authors = [""]
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["development", "debug_features"]
|
default = ["development", "debug_features", "gamecube-adapter"]
|
||||||
development = ["bevy/dynamic_linking", "bevy/file_watcher", "bevy/embedded_watcher"]
|
development = ["bevy/dynamic_linking", "bevy/file_watcher", "bevy/embedded_watcher"]
|
||||||
debug_features = ["bevy/free_camera"]
|
debug_features = ["bevy/free_camera"]
|
||||||
|
gamecube-adapter = ["dep:gc-adapter-neo"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.19", features = ["asset_processor", "basis-universal", "compressed_image_saver", "bevy_settings"] }
|
bevy = { version = "0.19", features = ["asset_processor", "basis-universal", "compressed_image_saver", "bevy_settings"] }
|
||||||
@@ -34,7 +35,6 @@ strum = "0.28.0"
|
|||||||
strum_macros = "0.28.0"
|
strum_macros = "0.28.0"
|
||||||
bevy_asset_loader = "0.27.0"
|
bevy_asset_loader = "0.27.0"
|
||||||
ron_asset_manager = "0.9.0"
|
ron_asset_manager = "0.9.0"
|
||||||
gc-adapter-neo = { version = "1.1.1", features = ["libusb"] }
|
|
||||||
rhai = "1.26.0"
|
rhai = "1.26.0"
|
||||||
enum_cycling = "0.2.1"
|
enum_cycling = "0.2.1"
|
||||||
enum_cycling_derive = "0.2.1"
|
enum_cycling_derive = "0.2.1"
|
||||||
@@ -49,3 +49,6 @@ inherits = "release"
|
|||||||
lto = "thin"
|
lto = "thin"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
strip = "symbols"
|
strip = "symbols"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
||||||
|
gc-adapter-neo = { version = "1.1.1", features = ["libusb"], optional = true }
|
||||||
|
|||||||
@@ -107,15 +107,11 @@ impl FighterStateImpl for JumpSquatState {
|
|||||||
|
|
||||||
fn on_enter(&mut self, state_context: &mut EnterContext) {
|
fn on_enter(&mut self, state_context: &mut EnterContext) {
|
||||||
state_context.play_animation(AnimKind::JumpSquat, false);
|
state_context.play_animation(AnimKind::JumpSquat, false);
|
||||||
// Preserve buffered inputs while jump squat makes the transition
|
|
||||||
// temporarily unavailable, matching Ultimate/HDR-style hold input.
|
|
||||||
state_context.input.enable_hold_all(10);
|
state_context.input.enable_hold_all(10);
|
||||||
state_context.input.clear_command(FighterCommands::Jump);
|
state_context.input.clear_command(FighterCommands::Jump);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, state_context: &mut crate::fighter::state::ExitContext) {
|
fn on_exit(&mut self, state_context: &mut crate::fighter::state::ExitContext) {
|
||||||
// The hold policy is state-scoped and must never leak into the next
|
|
||||||
// state. Command lifetime itself remains independent of this policy.
|
|
||||||
state_context.input.disable_hold_all();
|
state_context.input.disable_hold_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-10
@@ -1,9 +1,4 @@
|
|||||||
//! Rollback-safe input history and command buffering.
|
//! Rollback-safe input history and command buffering.
|
||||||
//!
|
|
||||||
//! Raw mapped bindings, button edges, and command lifetimes are deliberately
|
|
||||||
//! separate. This preserves combinations such as pressing a second shield
|
|
||||||
//! binding while the first one is held, while still allowing a command to
|
|
||||||
//! survive after its source button is released.
|
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_ggrs::{PlayerInputs, Rollback};
|
use bevy_ggrs::{PlayerInputs, Rollback};
|
||||||
@@ -276,14 +271,12 @@ impl FighterInput {
|
|||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds all inputs for n frames
|
||||||
pub fn enable_hold_all(&mut self, max_frames: u16) {
|
pub fn enable_hold_all(&mut self, max_frames: u16) {
|
||||||
self.hold_all = HoldLimit::from_max_frames(max_frames);
|
self.hold_all = HoldLimit::from_max_frames(max_frames);
|
||||||
self.latch_active_commands();
|
self.latch_active_commands();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stops enrolling commands in the global hold buffer. Commands already
|
|
||||||
/// latched retain their remaining lifetime so they can cross a state
|
|
||||||
/// boundary, such as jump squat into the first airborne frame.
|
|
||||||
pub fn disable_hold_all(&mut self) {
|
pub fn disable_hold_all(&mut self) {
|
||||||
self.hold_all = HoldLimit::Disabled;
|
self.hold_all = HoldLimit::Disabled;
|
||||||
}
|
}
|
||||||
@@ -553,8 +546,6 @@ pub fn postprocess_input(
|
|||||||
input.set_attack_command_type(attack_type);
|
input.set_attack_command_type(attack_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance each command's independently latched persistence. Physical
|
|
||||||
// source state is intentionally irrelevant after recognition.
|
|
||||||
for command in FighterCommands::iter() {
|
for command in FighterCommands::iter() {
|
||||||
input.update_hold(command);
|
input.update_hold(command);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ use bevy::input::gamepad::{
|
|||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use super::poll::{GcAdapterSnapshot, GcPortState};
|
use super::GcPorts;
|
||||||
|
use super::poll::GcAdapterSnapshot;
|
||||||
|
|
||||||
/// GameCube adapters report 4 ports.
|
/// GameCube adapters report 4 ports.
|
||||||
pub const GC_PORT_COUNT: usize = 4;
|
pub const GC_PORT_COUNT: usize = 4;
|
||||||
@@ -23,15 +24,6 @@ const GC_ADAPTER_PID: u16 = 0x0337;
|
|||||||
#[derive(Component, Debug, Clone, Copy)]
|
#[derive(Component, Debug, Clone, Copy)]
|
||||||
pub struct GcPort(pub u8);
|
pub struct GcPort(pub u8);
|
||||||
|
|
||||||
/// Tracks which entity (if any) represents each of the 4 adapter ports,
|
|
||||||
/// and the last snapshot seen, so both systems below can diff instead of
|
|
||||||
/// re-deriving state every frame.
|
|
||||||
#[derive(Resource, Default)]
|
|
||||||
pub struct GcPorts {
|
|
||||||
pub entities: [Option<Entity>; GC_PORT_COUNT],
|
|
||||||
last: [GcPortState; GC_PORT_COUNT],
|
|
||||||
}
|
|
||||||
|
|
||||||
fn passthrough_gamepad_settings() -> GamepadSettings {
|
fn passthrough_gamepad_settings() -> GamepadSettings {
|
||||||
let mut settings = GamepadSettings::default();
|
let mut settings = GamepadSettings::default();
|
||||||
for axis in GamepadAxis::all() {
|
for axis in GamepadAxis::all() {
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
pub mod bridge;
|
pub mod bridge;
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
pub mod poll;
|
pub mod poll;
|
||||||
|
|
||||||
pub use bridge::{GC_PORT_COUNT, GcPort, GcPorts};
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
|
pub use bridge::{GC_PORT_COUNT, GcPort};
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
pub use poll::{GcAdapterSnapshot, GcPortState};
|
pub use poll::{GcAdapterSnapshot, GcPortState};
|
||||||
|
|
||||||
|
#[derive(Resource, Default)]
|
||||||
|
pub struct GcPorts {
|
||||||
|
pub entities: [Option<Entity>; 4],
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
|
pub(super) last: [poll::GcPortState; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
use bevy::input::InputSystems;
|
use bevy::input::InputSystems;
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
use bevy::input::gamepad::{gamepad_connection_system, gamepad_event_processing_system};
|
use bevy::input::gamepad::{gamepad_connection_system, gamepad_event_processing_system};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
@@ -15,6 +28,8 @@ impl Plugin for GamecubeAdapterPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<GcPorts>();
|
app.init_resource::<GcPorts>();
|
||||||
|
|
||||||
|
#[cfg(all(feature = "gamecube-adapter", not(target_os = "windows")))]
|
||||||
|
{
|
||||||
let Ok(snapshot) = poll::spawn_poll_thread() else {
|
let Ok(snapshot) = poll::spawn_poll_thread() else {
|
||||||
// No adapter connected; leave GcPorts empty and skip wiring the
|
// No adapter connected; leave GcPorts empty and skip wiring the
|
||||||
// polling systems.
|
// polling systems.
|
||||||
@@ -32,4 +47,5 @@ impl Plugin for GamecubeAdapterPlugin {
|
|||||||
.in_set(InputSystems),
|
.in_set(InputSystems),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user