mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-03-31 02:32:44 +00:00
Initial
This commit is contained in:
parent
03cac66d5c
commit
98edfc6160
9 changed files with 368 additions and 274 deletions
|
@ -15,6 +15,7 @@ bitflags = "1.2.1"
|
||||||
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
parking_lot = { version = "0.12.0", features = ["nightly"] }
|
||||||
include-flate = "0.1.4"
|
include-flate = "0.1.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
modular-bitfield = "0.11.2"
|
||||||
owo-colors = "2.1.0"
|
owo-colors = "2.1.0"
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.12.0"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::fs;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use skyline::nn::hid::NpadGcState;
|
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
|
use crate::common::input::*;
|
||||||
use crate::consts::DEV_TOML_PATH;
|
use crate::consts::DEV_TOML_PATH;
|
||||||
use crate::logging::info;
|
use crate::logging::info;
|
||||||
|
|
||||||
|
@ -55,17 +55,9 @@ impl DevConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_get_npad_state(state: *mut NpadGcState, _controller_id: *const u32) {
|
pub fn handle_final_input_mapping(player_idx: i32, controller_struct: &mut SomeControllerStruct) {
|
||||||
let a_press = 1 << 0;
|
let current_buttons = controller_struct.controller.current_buttons;
|
||||||
let l_press = 1 << 6;
|
if player_idx == 0 && current_buttons.l() && current_buttons.r() && current_buttons.a() {
|
||||||
let r_press = 1 << 7;
|
|
||||||
let buttons;
|
|
||||||
unsafe {
|
|
||||||
buttons = (*state).Buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Occurs on L+R+A
|
|
||||||
if (buttons & a_press > 0) && (buttons & l_press > 0) && (buttons & r_press > 0) {
|
|
||||||
let mut dev_config = DEV_CONFIG.lock();
|
let mut dev_config = DEV_CONFIG.lock();
|
||||||
*dev_config = DevConfig::load_from_toml();
|
*dev_config = DevConfig::load_from_toml();
|
||||||
}
|
}
|
||||||
|
|
291
src/common/input.rs
Normal file
291
src/common/input.rs
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
#![allow(dead_code)] // TODO: Yeah don't do this
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use modular_bitfield::{bitfield, specifiers::*};
|
||||||
|
|
||||||
|
// Need to define necesary structures here. Probably should move to consts or something. Realistically, should be in skyline smash prob tho.
|
||||||
|
|
||||||
|
// Final final controls used for controlmodule
|
||||||
|
// can I actually derive these?
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ControlModuleInternal {
|
||||||
|
pub vtable: *mut u8,
|
||||||
|
pub controller_index: i32,
|
||||||
|
pub buttons: Buttons,
|
||||||
|
pub stick_x: f32,
|
||||||
|
pub stick_y: f32,
|
||||||
|
pub padding: [f32; 2],
|
||||||
|
pub unk: [u32; 8],
|
||||||
|
pub clamped_lstick_x: f32,
|
||||||
|
pub clamped_lstick_y: f32,
|
||||||
|
pub padding2: [f32; 2],
|
||||||
|
pub clamped_rstick_x: f32,
|
||||||
|
pub clamped_rstick_y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlModuleInternal {
|
||||||
|
pub fn _clear(&mut self) {
|
||||||
|
// Try to nullify controls so we can't control player 1 during recording
|
||||||
|
self.stick_x = 0.0;
|
||||||
|
self.stick_y = 0.0;
|
||||||
|
self.buttons = Buttons::empty();
|
||||||
|
self.clamped_lstick_x = 0.0;
|
||||||
|
self.clamped_lstick_y = 0.0;
|
||||||
|
self.clamped_rstick_x = 0.0;
|
||||||
|
self.clamped_rstick_y = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ControlModuleStored {
|
||||||
|
// Custom type for saving only necessary controls/not saving vtable
|
||||||
|
pub buttons: Buttons,
|
||||||
|
pub stick_x: f32,
|
||||||
|
pub stick_y: f32,
|
||||||
|
pub padding: [f32; 2],
|
||||||
|
pub unk: [u32; 8],
|
||||||
|
pub clamped_lstick_x: f32,
|
||||||
|
pub clamped_lstick_y: f32,
|
||||||
|
pub padding2: [f32; 2],
|
||||||
|
pub clamped_rstick_x: f32,
|
||||||
|
pub clamped_rstick_y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-ordered bitfield the game uses for buttons
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ButtonBitfield {
|
||||||
|
pub dpad_up: bool,
|
||||||
|
pub dpad_right: bool,
|
||||||
|
pub dpad_down: bool,
|
||||||
|
pub dpad_left: bool,
|
||||||
|
pub x: bool,
|
||||||
|
pub a: bool,
|
||||||
|
pub b: bool,
|
||||||
|
pub y: bool,
|
||||||
|
pub l: bool,
|
||||||
|
pub r: bool,
|
||||||
|
pub zl: bool,
|
||||||
|
pub zr: bool,
|
||||||
|
pub left_sl: bool,
|
||||||
|
pub left_sr: bool,
|
||||||
|
pub right_sl: bool,
|
||||||
|
pub right_sr: bool,
|
||||||
|
pub stick_l: bool,
|
||||||
|
pub stick_r: bool,
|
||||||
|
pub plus: bool,
|
||||||
|
pub minus: bool,
|
||||||
|
pub l_up: bool,
|
||||||
|
pub l_right: bool,
|
||||||
|
pub l_down: bool,
|
||||||
|
pub l_left: bool,
|
||||||
|
pub r_up: bool,
|
||||||
|
pub r_right: bool,
|
||||||
|
pub r_down: bool,
|
||||||
|
pub r_left: bool,
|
||||||
|
pub real_digital_l: bool,
|
||||||
|
pub real_digital_r: bool,
|
||||||
|
pub unused: B2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Controller style declaring what kind of controller is being used
|
||||||
|
#[derive(PartialEq, Eq, Default, Debug, Copy, Clone)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum ControllerStyle {
|
||||||
|
#[default]
|
||||||
|
Handheld = 0x1,
|
||||||
|
DualJoycon = 0x2,
|
||||||
|
LeftJoycon = 0x3,
|
||||||
|
RightJoycon = 0x4,
|
||||||
|
ProController = 0x5,
|
||||||
|
DebugPad = 0x6, // probably
|
||||||
|
GCController = 0x7,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AutorepeatInfo {
|
||||||
|
field: [u8; 0x18],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can map any of these over any button - what does this mean?
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum InputKind {
|
||||||
|
Attack = 0x0,
|
||||||
|
Special = 0x1,
|
||||||
|
Jump = 0x2,
|
||||||
|
Guard = 0x3,
|
||||||
|
Grab = 0x4,
|
||||||
|
SmashAttack = 0x5,
|
||||||
|
AppealHi = 0xA,
|
||||||
|
AppealS = 0xB,
|
||||||
|
AppealLw = 0xC,
|
||||||
|
Unset = 0xD,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x50 Byte struct containing the information for controller mappings
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ControllerMapping {
|
||||||
|
pub gc_l: InputKind,
|
||||||
|
pub gc_r: InputKind,
|
||||||
|
pub gc_z: InputKind,
|
||||||
|
pub gc_dup: InputKind,
|
||||||
|
pub gc_dlr: InputKind,
|
||||||
|
pub gc_ddown: InputKind,
|
||||||
|
pub gc_a: InputKind,
|
||||||
|
pub gc_b: InputKind,
|
||||||
|
pub gc_cstick: InputKind,
|
||||||
|
pub gc_y: InputKind,
|
||||||
|
pub gc_x: InputKind,
|
||||||
|
pub gc_rumble: bool,
|
||||||
|
pub gc_absmash: bool,
|
||||||
|
pub gc_tapjump: bool,
|
||||||
|
pub gc_sensitivity: u8,
|
||||||
|
// 0xF
|
||||||
|
pub pro_l: InputKind,
|
||||||
|
pub pro_r: InputKind,
|
||||||
|
pub pro_zl: InputKind,
|
||||||
|
pub pro_zr: InputKind,
|
||||||
|
pub pro_dup: InputKind,
|
||||||
|
pub pro_dlr: InputKind,
|
||||||
|
pub pro_ddown: InputKind,
|
||||||
|
pub pro_a: InputKind,
|
||||||
|
pub pro_b: InputKind,
|
||||||
|
pub pro_cstick: InputKind,
|
||||||
|
pub pro_x: InputKind,
|
||||||
|
pub pro_y: InputKind,
|
||||||
|
pub pro_rumble: bool,
|
||||||
|
pub pro_absmash: bool,
|
||||||
|
pub pro_tapjump: bool,
|
||||||
|
pub pro_sensitivity: u8,
|
||||||
|
// 0x1F
|
||||||
|
pub joy_shoulder: InputKind,
|
||||||
|
pub joy_zshoulder: InputKind,
|
||||||
|
pub joy_sl: InputKind,
|
||||||
|
pub joy_sr: InputKind,
|
||||||
|
pub joy_up: InputKind,
|
||||||
|
pub joy_right: InputKind,
|
||||||
|
pub joy_left: InputKind,
|
||||||
|
pub joy_down: InputKind,
|
||||||
|
pub joy_rumble: bool,
|
||||||
|
pub joy_absmash: bool,
|
||||||
|
pub joy_tapjump: bool,
|
||||||
|
pub joy_sensitivity: u8,
|
||||||
|
// 0x2B
|
||||||
|
pub _2b: u8,
|
||||||
|
pub _2c: u8,
|
||||||
|
pub _2d: u8,
|
||||||
|
pub _2e: u8,
|
||||||
|
pub _2f: u8,
|
||||||
|
pub _30: u8,
|
||||||
|
pub _31: u8,
|
||||||
|
pub _32: u8,
|
||||||
|
pub is_absmash: bool,
|
||||||
|
pub _34: [u8; 0x1C],
|
||||||
|
}
|
||||||
|
|
||||||
|
//type Buttons = u32; // may need to actually implement (like label and such)? Not for now though
|
||||||
|
bitflags! {
|
||||||
|
pub struct Buttons: u32 {
|
||||||
|
const ATTACK = 0x1;
|
||||||
|
const SPECIAL = 0x2;
|
||||||
|
const JUMP = 0x4;
|
||||||
|
const GUARD = 0x8;
|
||||||
|
const CATCH = 0x10;
|
||||||
|
const SMASH = 0x20;
|
||||||
|
const JUMP_MINI = 0x40;
|
||||||
|
const CSTICK_ON = 0x80;
|
||||||
|
const STOCK_SHARE = 0x100;
|
||||||
|
const ATTACK_RAW = 0x200;
|
||||||
|
const APPEAL_HI = 0x400;
|
||||||
|
const SPECIAL_RAW = 0x800;
|
||||||
|
const APPEAL_LW = 0x1000;
|
||||||
|
const APPEAL_SL = 0x2000;
|
||||||
|
const APPEAL_SR = 0x4000;
|
||||||
|
const FLICK_JUMP = 0x8000;
|
||||||
|
const GUARD_HOLD = 0x10000;
|
||||||
|
const SPECIAL_RAW2 = 0x20000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller class used internally by the game
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Controller {
|
||||||
|
pub vtable: u64,
|
||||||
|
pub current_buttons: ButtonBitfield,
|
||||||
|
pub previous_buttons: ButtonBitfield,
|
||||||
|
pub left_stick_x: f32,
|
||||||
|
pub left_stick_y: f32,
|
||||||
|
pub left_trigger: f32,
|
||||||
|
pub _left_padding: u32,
|
||||||
|
pub right_stick_x: f32,
|
||||||
|
pub right_stick_y: f32,
|
||||||
|
pub right_trigger: f32,
|
||||||
|
pub _right_padding: u32,
|
||||||
|
pub gyro: [f32; 4],
|
||||||
|
pub button_timespan: AutorepeatInfo,
|
||||||
|
pub lstick_timespan: AutorepeatInfo,
|
||||||
|
pub rstick_timespan: AutorepeatInfo,
|
||||||
|
pub just_down: ButtonBitfield,
|
||||||
|
pub just_release: ButtonBitfield,
|
||||||
|
pub autorepeat_keys: u32,
|
||||||
|
pub autorepeat_threshold: u32,
|
||||||
|
pub autorepeat_initial_press_threshold: u32,
|
||||||
|
pub style: ControllerStyle,
|
||||||
|
pub controller_id: u32,
|
||||||
|
pub primary_controller_color1: u32,
|
||||||
|
pub primary_controller_color2: u32,
|
||||||
|
pub secondary_controller_color1: u32,
|
||||||
|
pub secondary_controller_color2: u32,
|
||||||
|
pub led_pattern: u8,
|
||||||
|
pub button_autorepeat_initial_press: bool,
|
||||||
|
pub lstick_autorepeat_initial_press: bool,
|
||||||
|
pub rstick_autorepeat_initial_press: bool,
|
||||||
|
pub is_valid_controller: bool,
|
||||||
|
pub _x_b9: [u8; 2],
|
||||||
|
pub is_connected: bool,
|
||||||
|
pub is_left_connected: bool,
|
||||||
|
pub is_right_connected: bool,
|
||||||
|
pub is_wired: bool,
|
||||||
|
pub is_left_wired: bool,
|
||||||
|
pub is_right_wired: bool,
|
||||||
|
pub _x_c1: [u8; 3],
|
||||||
|
pub npad_number: u32,
|
||||||
|
pub _x_c8: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeControllerStruct used in hooked function - need to ask blujay what this is again
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SomeControllerStruct {
|
||||||
|
padding: [u8; 0x10],
|
||||||
|
pub controller: &'static mut Controller,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define struct used for final controller inputs
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MappedInputs {
|
||||||
|
pub buttons: Buttons,
|
||||||
|
pub lstick_x: i8,
|
||||||
|
pub lstick_y: i8,
|
||||||
|
pub rstick_x: i8,
|
||||||
|
pub rstick_y: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MappedInputs {
|
||||||
|
// pub needed?
|
||||||
|
pub fn default() -> MappedInputs {
|
||||||
|
MappedInputs {
|
||||||
|
buttons: Buttons::empty(),
|
||||||
|
lstick_x: 0,
|
||||||
|
lstick_y: 0,
|
||||||
|
rstick_x: 0,
|
||||||
|
rstick_y: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use std::fs;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use skyline::nn::hid::{GetNpadStyleSet, NpadGcState};
|
use skyline::nn::hid::GetNpadStyleSet;
|
||||||
use training_mod_consts::MenuJsonStruct;
|
use training_mod_consts::MenuJsonStruct;
|
||||||
|
|
||||||
use training_mod_tui::AppPage;
|
use training_mod_tui::AppPage;
|
||||||
|
@ -10,12 +10,12 @@ use training_mod_tui::AppPage;
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
use crate::consts::MENU_OPTIONS_PATH;
|
use crate::consts::MENU_OPTIONS_PATH;
|
||||||
use crate::events::{Event, EVENT_QUEUE};
|
use crate::events::{Event, EVENT_QUEUE};
|
||||||
|
use crate::input::*;
|
||||||
use crate::logging::*;
|
use crate::logging::*;
|
||||||
|
|
||||||
// This is a special frame counter that will tick on draw()
|
// This is a special frame counter that will tick on draw()
|
||||||
// We'll count how long the menu has been open
|
// We'll count how long the menu has been open
|
||||||
pub static mut FRAME_COUNTER: u32 = 0;
|
pub static mut FRAME_COUNTER: u32 = 0;
|
||||||
const MENU_INPUT_WAIT_FRAMES: u32 = 30;
|
|
||||||
const MENU_CLOSE_WAIT_FRAMES: u32 = 60;
|
const MENU_CLOSE_WAIT_FRAMES: u32 = 60;
|
||||||
pub static mut QUICK_MENU_ACTIVE: bool = false;
|
pub static mut QUICK_MENU_ACTIVE: bool = false;
|
||||||
|
|
||||||
|
@ -76,177 +76,6 @@ pub fn spawn_menu() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ButtonPresses {
|
|
||||||
pub a: ButtonPress,
|
|
||||||
pub b: ButtonPress,
|
|
||||||
pub x: ButtonPress,
|
|
||||||
pub y: ButtonPress,
|
|
||||||
pub r: ButtonPress,
|
|
||||||
pub l: ButtonPress,
|
|
||||||
pub zr: ButtonPress,
|
|
||||||
pub zl: ButtonPress,
|
|
||||||
pub left: ButtonPress,
|
|
||||||
pub right: ButtonPress,
|
|
||||||
pub up: ButtonPress,
|
|
||||||
pub down: ButtonPress,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ButtonPress {
|
|
||||||
pub prev_frame_is_pressed: bool,
|
|
||||||
pub is_pressed: bool,
|
|
||||||
pub lockout_frames: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ButtonPress {
|
|
||||||
pub fn read_press(&mut self) -> bool {
|
|
||||||
let is_pressed = self.is_pressed;
|
|
||||||
if self.is_pressed {
|
|
||||||
self.is_pressed = false;
|
|
||||||
if self.lockout_frames == 0 {
|
|
||||||
self.prev_frame_is_pressed = true;
|
|
||||||
self.lockout_frames = 10;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.lockout_frames > 0 {
|
|
||||||
self.lockout_frames -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.prev_frame_is_pressed = is_pressed;
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static mut BUTTON_PRESSES: ButtonPresses = ButtonPresses {
|
|
||||||
a: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
b: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
x: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
y: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
r: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
l: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
zr: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
zl: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
left: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
right: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
up: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
down: ButtonPress {
|
|
||||||
prev_frame_is_pressed: false,
|
|
||||||
is_pressed: false,
|
|
||||||
lockout_frames: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn handle_get_npad_state(state: *mut NpadGcState, controller_id: *const u32) {
|
|
||||||
unsafe {
|
|
||||||
let update_count = (*state).updateCount;
|
|
||||||
let flags = (*state).Flags;
|
|
||||||
if QUICK_MENU_ACTIVE {
|
|
||||||
if (*state).Buttons & (1 << 0) > 0 {
|
|
||||||
BUTTON_PRESSES.a.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 1) > 0 {
|
|
||||||
BUTTON_PRESSES.b.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 2) > 0 {
|
|
||||||
BUTTON_PRESSES.x.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 3) > 0 {
|
|
||||||
BUTTON_PRESSES.y.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 6) > 0 {
|
|
||||||
BUTTON_PRESSES.l.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 7) > 0 {
|
|
||||||
BUTTON_PRESSES.r.is_pressed = true;
|
|
||||||
}
|
|
||||||
// Special case for frame-by-frame
|
|
||||||
if FRAME_COUNTER > MENU_INPUT_WAIT_FRAMES && (*state).Buttons & (1 << 8) > 0 {
|
|
||||||
BUTTON_PRESSES.zl.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & (1 << 9) > 0 {
|
|
||||||
BUTTON_PRESSES.zr.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & ((1 << 12) | (1 << 16)) > 0 {
|
|
||||||
BUTTON_PRESSES.left.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & ((1 << 14) | (1 << 18)) > 0 {
|
|
||||||
BUTTON_PRESSES.right.is_pressed = true;
|
|
||||||
}
|
|
||||||
if (*state).Buttons & ((1 << 15) | (1 << 19)) > 0 {
|
|
||||||
BUTTON_PRESSES.down.is_pressed = true;
|
|
||||||
}
|
|
||||||
// Special case for "UP" in menu open button combo
|
|
||||||
if FRAME_COUNTER > MENU_INPUT_WAIT_FRAMES
|
|
||||||
&& (*state).Buttons & ((1 << 13) | (1 << 17)) > 0
|
|
||||||
{
|
|
||||||
BUTTON_PRESSES.up.is_pressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For digital triggers: these pressed 1/3 of the way mean we should consider a press
|
|
||||||
if controller_is_gcc(*controller_id) {
|
|
||||||
if (*state).LTrigger >= 0x2AAA {
|
|
||||||
BUTTON_PRESSES.l.is_pressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*state).RTrigger >= 0x2AAA {
|
|
||||||
BUTTON_PRESSES.r.is_pressed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're here, remove all other Npad presses...
|
|
||||||
// Should we exclude the home button?
|
|
||||||
(*state) = NpadGcState::default();
|
|
||||||
(*state).updateCount = update_count;
|
|
||||||
(*state).Flags = flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref QUICK_MENU_APP: Mutex<training_mod_tui::App<'static>> = Mutex::new(
|
pub static ref QUICK_MENU_APP: Mutex<training_mod_tui::App<'static>> = Mutex::new(
|
||||||
training_mod_tui::App::new(unsafe { ui_menu(MENU) }, unsafe {
|
training_mod_tui::App::new(unsafe { ui_menu(MENU) }, unsafe {
|
||||||
|
@ -256,22 +85,26 @@ lazy_static! {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
pub static ref P1_CONTROLLER_STATE: Mutex<Controller> = Mutex::new(Controller::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn controller_is_gcc(controller_id: u32) -> bool {
|
pub fn handle_final_input_mapping(
|
||||||
let style_set = GetNpadStyleSet(&controller_id as *const _);
|
player_idx: i32,
|
||||||
(style_set.flags & (1 << 5)) > 0
|
controller_struct: &mut SomeControllerStruct,
|
||||||
}
|
out: *mut MappedInputs,
|
||||||
|
) {
|
||||||
pub unsafe fn p1_controller_is_gcc() -> bool {
|
unsafe {
|
||||||
let p1_controller_id = crate::training::input_delay::p1_controller_id();
|
if QUICK_MENU_ACTIVE && player_idx == 0 {
|
||||||
controller_is_gcc(p1_controller_id)
|
*P1_CONTROLLER_STATE.lock() = *controller_struct.controller;
|
||||||
|
// If we're here, remove all other presses
|
||||||
|
*out = MappedInputs::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn quick_menu_loop() {
|
pub unsafe fn quick_menu_loop() {
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||||
let button_presses = &mut BUTTON_PRESSES;
|
|
||||||
let mut received_input = true;
|
let mut received_input = true;
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(16));
|
std::thread::sleep(std::time::Duration::from_millis(16));
|
||||||
|
@ -291,15 +124,16 @@ pub unsafe fn quick_menu_loop() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_gcc = p1_controller_is_gcc();
|
let p1_controller_state = *P1_CONTROLLER_STATE.data_ptr();
|
||||||
|
let is_gcc = p1_controller_state.style == ControllerStyle::GCController;
|
||||||
|
let button_presses = p1_controller_state.just_down;
|
||||||
|
|
||||||
let app = &mut *QUICK_MENU_APP.data_ptr();
|
let app = &mut *QUICK_MENU_APP.data_ptr();
|
||||||
button_presses.a.read_press().then(|| {
|
button_presses.a().then(|| {
|
||||||
app.on_a();
|
app.on_a();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
let b_press = &mut button_presses.b;
|
button_presses.b().then(|| {
|
||||||
b_press.read_press().then(|| {
|
|
||||||
received_input = true;
|
received_input = true;
|
||||||
if app.page != AppPage::SUBMENU {
|
if app.page != AppPage::SUBMENU {
|
||||||
app.on_b()
|
app.on_b()
|
||||||
|
@ -312,21 +146,21 @@ pub unsafe fn quick_menu_loop() {
|
||||||
EVENT_QUEUE.push(Event::menu_open(menu_json));
|
EVENT_QUEUE.push(Event::menu_open(menu_json));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
button_presses.x.read_press().then(|| {
|
button_presses.x().then(|| {
|
||||||
app.save_defaults();
|
app.save_defaults();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.y.read_press().then(|| {
|
button_presses.y().then(|| {
|
||||||
app.reset_all_submenus();
|
app.reset_all_submenus();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.l.read_press().then(|| {
|
button_presses.l().then(|| {
|
||||||
if is_gcc {
|
if is_gcc {
|
||||||
app.previous_tab();
|
app.previous_tab();
|
||||||
}
|
}
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.r.read_press().then(|| {
|
button_presses.r().then(|| {
|
||||||
if is_gcc {
|
if is_gcc {
|
||||||
app.next_tab();
|
app.next_tab();
|
||||||
} else {
|
} else {
|
||||||
|
@ -334,13 +168,13 @@ pub unsafe fn quick_menu_loop() {
|
||||||
}
|
}
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.zl.read_press().then(|| {
|
button_presses.zl().then(|| {
|
||||||
if !is_gcc {
|
if !is_gcc {
|
||||||
app.previous_tab();
|
app.previous_tab();
|
||||||
}
|
}
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.zr.read_press().then(|| {
|
button_presses.zr().then(|| {
|
||||||
if !is_gcc {
|
if !is_gcc {
|
||||||
app.next_tab();
|
app.next_tab();
|
||||||
} else {
|
} else {
|
||||||
|
@ -348,19 +182,19 @@ pub unsafe fn quick_menu_loop() {
|
||||||
}
|
}
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.left.read_press().then(|| {
|
button_presses.l_left().then(|| {
|
||||||
app.on_left();
|
app.on_left();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.right.read_press().then(|| {
|
button_presses.l_right().then(|| {
|
||||||
app.on_right();
|
app.on_right();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.up.read_press().then(|| {
|
button_presses.l_up().then(|| {
|
||||||
app.on_up();
|
app.on_up();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
button_presses.down.read_press().then(|| {
|
button_presses.l_down().then(|| {
|
||||||
app.on_down();
|
app.on_down();
|
||||||
received_input = true;
|
received_input = true;
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub mod button_config;
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod dev_config;
|
pub mod dev_config;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
|
pub mod input;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
pub mod raygun_printer;
|
pub mod raygun_printer;
|
||||||
pub mod release;
|
pub mod release;
|
||||||
|
|
|
@ -1,51 +1,30 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::common::input::*;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use skyline::nn::hid::{GetNpadStyleSet, NpadGcState};
|
|
||||||
|
|
||||||
use crate::common::MENU;
|
use crate::common::MENU;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref P1_DELAYED_NPAD_STATES: Mutex<VecDeque<NpadGcState>> = Mutex::new(VecDeque::new());
|
static ref P1_DELAYED_INPUT_MAPPINGS: Mutex<VecDeque<MappedInputs>> =
|
||||||
|
Mutex::new(VecDeque::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn p1_controller_id() -> u32 {
|
pub fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs) {
|
||||||
let min_controller_id = (0..8)
|
|
||||||
.filter(|i| GetNpadStyleSet(i as *const _).flags != 0)
|
|
||||||
.min()
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let handheld_id = 0x20;
|
|
||||||
if GetNpadStyleSet(&handheld_id as *const _).flags != 0 {
|
|
||||||
handheld_id
|
|
||||||
} else {
|
|
||||||
min_controller_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_get_npad_state(state: *mut NpadGcState, controller_id: *const u32) {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if crate::common::is_training_mode() && *controller_id == p1_controller_id() {
|
if player_idx == 0 {
|
||||||
let mut delayed_states = P1_DELAYED_NPAD_STATES.lock();
|
let mut delayed_mappings = P1_DELAYED_INPUT_MAPPINGS.lock();
|
||||||
let actual_state = *state;
|
let actual_mapping = *out;
|
||||||
|
|
||||||
if delayed_states.len() < MENU.input_delay.into_delay() as usize {
|
if delayed_mappings.len() < MENU.input_delay.into_delay() as usize {
|
||||||
let update_count = (*state).updateCount;
|
*out = MappedInputs::default();
|
||||||
let attributes = (*state).Flags;
|
} else if let Some(delayed_mapping) = delayed_mappings.back() {
|
||||||
*state = NpadGcState::default();
|
*out = *delayed_mapping;
|
||||||
(*state).updateCount = update_count;
|
|
||||||
(*state).Flags = attributes;
|
|
||||||
} else if let Some(delayed_state) = delayed_states.back() {
|
|
||||||
let update_count = (*state).updateCount;
|
|
||||||
let attributes = (*state).Flags;
|
|
||||||
*state = *delayed_state;
|
|
||||||
(*state).updateCount = update_count;
|
|
||||||
(*state).Flags = attributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delayed_states.push_front(actual_state);
|
delayed_mappings.push_front(actual_mapping);
|
||||||
delayed_states.truncate(MENU.input_delay.into_delay() as usize);
|
delayed_mappings.truncate(MENU.input_delay.into_delay() as usize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::common::button_config;
|
use crate::common::button_config;
|
||||||
use crate::common::consts::{FighterId, HitstunPlayback, OnOff};
|
use crate::common::consts::{FighterId, HitstunPlayback, OnOff};
|
||||||
|
use crate::common::input::*;
|
||||||
use crate::common::{get_module_accessor, is_in_hitstun, is_in_shieldstun, MENU};
|
use crate::common::{get_module_accessor, is_in_hitstun, is_in_shieldstun, MENU};
|
||||||
use crate::training::input_recording::structures::*;
|
|
||||||
use crate::training::mash;
|
use crate::training::mash;
|
||||||
use crate::training::ui::notifications::{clear_notifications, color_notification};
|
use crate::training::ui::notifications::{clear_notifications, color_notification};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -372,18 +372,7 @@ pub unsafe fn is_end_standby() -> bool {
|
||||||
lstick_movement || rstick_movement || buttons_pressed
|
lstick_movement || rstick_movement || buttons_pressed
|
||||||
}
|
}
|
||||||
|
|
||||||
static FIM_OFFSET: usize = 0x17504a0;
|
pub unsafe fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs) {
|
||||||
// TODO: Should we define all of our offsets in one file? Should at least be a good start for changing to be based on ASM instructions
|
|
||||||
#[skyline::hook(offset = FIM_OFFSET)]
|
|
||||||
unsafe fn handle_final_input_mapping(
|
|
||||||
mappings: *mut ControllerMapping,
|
|
||||||
player_idx: i32, // Is this the player index, or plugged in controller index? Need to check, assuming player for now - is this 0 indexed or 1?
|
|
||||||
out: *mut MappedInputs,
|
|
||||||
controller_struct: &mut SomeControllerStruct,
|
|
||||||
arg: bool,
|
|
||||||
) {
|
|
||||||
// go through the original mapping function first
|
|
||||||
original!()(mappings, player_idx, out, controller_struct, arg);
|
|
||||||
if player_idx == 0 {
|
if player_idx == 0 {
|
||||||
// if player 1
|
// if player 1
|
||||||
if INPUT_RECORD == Record {
|
if INPUT_RECORD == Record {
|
||||||
|
@ -524,5 +513,5 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
skyline::install_hooks!(set_cpu_controls, handle_final_input_mapping,);
|
skyline::install_hooks!(set_cpu_controls);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
|
use skyline::hooks::{getRegionAddress, InlineCtx, Region};
|
||||||
use skyline::nn::hid::*;
|
|
||||||
use skyline::nn::ro::LookupSymbol;
|
use skyline::nn::ro::LookupSymbol;
|
||||||
use smash::app::{self, enSEType, lua_bind::*, utility};
|
use smash::app::{self, enSEType, lua_bind::*, utility};
|
||||||
use smash::lib::lua_const::*;
|
use smash::lib::lua_const::*;
|
||||||
|
@ -11,6 +10,7 @@ use crate::common::{
|
||||||
is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
|
is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
|
||||||
};
|
};
|
||||||
use crate::hitbox_visualizer;
|
use crate::hitbox_visualizer;
|
||||||
|
use crate::input::*;
|
||||||
use crate::logging::*;
|
use crate::logging::*;
|
||||||
use crate::training::character_specific::items;
|
use crate::training::character_specific::items;
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ mod fast_fall;
|
||||||
mod full_hop;
|
mod full_hop;
|
||||||
pub mod input_delay;
|
pub mod input_delay;
|
||||||
mod input_record;
|
mod input_record;
|
||||||
mod input_recording;
|
|
||||||
mod mash;
|
mod mash;
|
||||||
mod reset;
|
mod reset;
|
||||||
pub mod save_states;
|
pub mod save_states;
|
||||||
|
@ -615,25 +614,30 @@ pub unsafe fn handle_reused_ui(
|
||||||
original!()(fighter_data, param_2)
|
original!()(fighter_data, param_2)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(improper_ctypes)]
|
static FIM_OFFSET: usize = 0x17504a0;
|
||||||
extern "C" {
|
// TODO: Should we define all of our offsets in one file? Should at least be a good start for changing to be based on ASM instructions
|
||||||
fn add_nn_hid_hook(callback: fn(*mut NpadGcState, *const u32));
|
#[skyline::hook(offset = FIM_OFFSET)]
|
||||||
|
unsafe fn handle_final_input_mapping(
|
||||||
|
mappings: *mut ControllerMapping,
|
||||||
|
player_idx: i32, // Is this the player index, or plugged in controller index? Need to check, assuming player for now - is this 0 indexed or 1?
|
||||||
|
out: *mut MappedInputs,
|
||||||
|
controller_struct: &mut SomeControllerStruct,
|
||||||
|
arg: bool,
|
||||||
|
) {
|
||||||
|
// go through the original mapping function first
|
||||||
|
original!()(mappings, player_idx, out, controller_struct, arg);
|
||||||
|
if !is_training_mode() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
menu::handle_final_input_mapping(player_idx, controller_struct, out);
|
||||||
|
dev_config::handle_final_input_mapping(player_idx, controller_struct);
|
||||||
|
input_delay::handle_final_input_mapping(player_idx, out);
|
||||||
|
input_record::handle_final_input_mapping(player_idx, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn training_mods() {
|
pub fn training_mods() {
|
||||||
info!("Applying training mods.");
|
info!("Applying training mods.");
|
||||||
|
|
||||||
// Input Mods
|
|
||||||
unsafe {
|
|
||||||
if let Some(_f) = (add_nn_hid_hook as *const ()).as_ref() {
|
|
||||||
add_nn_hid_hook(input_delay::handle_get_npad_state);
|
|
||||||
add_nn_hid_hook(menu::handle_get_npad_state);
|
|
||||||
add_nn_hid_hook(dev_config::handle_get_npad_state);
|
|
||||||
} else {
|
|
||||||
panic!("The NN-HID hook plugin could not be found and is required to add NRO hooks. Make sure libnn_hid_hook.nro is installed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LookupSymbol(
|
LookupSymbol(
|
||||||
&mut FIGHTER_MANAGER_ADDR,
|
&mut FIGHTER_MANAGER_ADDR,
|
||||||
|
@ -705,6 +709,8 @@ pub fn training_mods() {
|
||||||
handle_star_ko,
|
handle_star_ko,
|
||||||
// Clatter
|
// Clatter
|
||||||
clatter::hook_start_clatter,
|
clatter::hook_start_clatter,
|
||||||
|
// Input
|
||||||
|
handle_final_input_mapping
|
||||||
);
|
);
|
||||||
|
|
||||||
combo::init();
|
combo::init();
|
||||||
|
|
|
@ -6,7 +6,7 @@ use smash::ui2d::{SmashPane, SmashTextBox};
|
||||||
use training_mod_tui::gauge::GaugeState;
|
use training_mod_tui::gauge::GaugeState;
|
||||||
use training_mod_tui::{App, AppPage};
|
use training_mod_tui::{App, AppPage};
|
||||||
|
|
||||||
use crate::{common, common::menu::QUICK_MENU_ACTIVE};
|
use crate::{common, common::menu::QUICK_MENU_ACTIVE, input::*};
|
||||||
|
|
||||||
pub static NUM_MENU_TEXT_OPTIONS: usize = 33;
|
pub static NUM_MENU_TEXT_OPTIONS: usize = 33;
|
||||||
pub static _NUM_MENU_TABS: usize = 3;
|
pub static _NUM_MENU_TABS: usize = 3;
|
||||||
|
@ -405,7 +405,8 @@ pub unsafe fn draw(root_pane: &Pane) {
|
||||||
};
|
};
|
||||||
let tab_titles = [prev_tab, tab_selected, next_tab].map(|idx| app_tabs[idx]);
|
let tab_titles = [prev_tab, tab_selected, next_tab].map(|idx| app_tabs[idx]);
|
||||||
|
|
||||||
let is_gcc = common::menu::p1_controller_is_gcc();
|
let is_gcc =
|
||||||
|
(*common::menu::P1_CONTROLLER_STATE.data_ptr()).style == ControllerStyle::GCController;
|
||||||
let button_mapping = if is_gcc {
|
let button_mapping = if is_gcc {
|
||||||
GCC_BUTTON_MAPPING.clone()
|
GCC_BUTTON_MAPPING.clone()
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue