diff --git a/Cargo.toml b/Cargo.toml index fa71eec..ceeebff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" bitflags = "1.2.1" parking_lot = { version = "0.11.0", features = ["nightly"] } lazy_static = "1.4.0" +owo-colors = "1.1.3" +paste = "1.0" [profile.dev] panic = "abort" diff --git a/src/lib.rs b/src/lib.rs index ad6e06b..d16f58a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ use training::combo::FRAME_ADVANTAGE; use skyline::libc::{c_void, fclose, fopen, fwrite, mkdir}; use skyline::nro::{self, NroInfo}; +use owo_colors::OwoColorize; + fn nro_main(nro: &NroInfo<'_>) { if nro.module.isLoaded { return; @@ -42,7 +44,14 @@ macro_rules! c_str { #[skyline::main(name = "training_modpack")] pub fn main() { - println!("[Training Modpack] Initialized."); + macro_rules! log { + ($($arg:tt)*) => { + print!("{}", "[Training Modpack] ".green()); + println!($($arg)*); + }; + } + + log!("Initialized."); hitbox_visualizer::hitbox_visualization(); hazard_manager::hazard_manager(); training::training_mods(); @@ -50,14 +59,14 @@ pub fn main() { unsafe { let mut buffer = format!("{:x}", MENU as *const _ as u64); - println!( - "[Training Modpack] Writing training_modpack.log with {}...", + log!( + "Writing training_modpack.log with {}...", buffer ); mkdir(c_str!("sd:/TrainingModpack/"), 0777); // Only necessary upon version upgrade. - // println!("[Training Modpack] Removing training_modpack_menu.conf..."); + // log!("[Training Modpack] Removing training_modpack_menu.conf..."); // remove(c_str!("sd:/TrainingModpack/training_modpack_menu.conf")); let mut f = fopen( @@ -71,8 +80,8 @@ pub fn main() { } buffer = format!("{:x}", &FRAME_ADVANTAGE as *const _ as u64); - println!( - "[Training Modpack] Writing training_modpack_frame_adv.log with {}...", + log!( + "Writing training_modpack_frame_adv.log with {}...", buffer ); diff --git a/src/training/input_delay.rs b/src/training/input_delay.rs index 3cbf6f8..6e1830f 100644 --- a/src/training/input_delay.rs +++ b/src/training/input_delay.rs @@ -1,7 +1,8 @@ use lazy_static::lazy_static; use parking_lot::Mutex; -use skyline::nn::hid::NpadHandheldState; +use skyline::nn::hid::{NpadHandheldState, GetNpadStyleSet}; use std::collections::VecDeque; +use crate::common::MENU; lazy_static! { static ref P1_DELAYED_NPAD_STATES: Mutex> = @@ -9,7 +10,6 @@ lazy_static! { } pub unsafe fn p1_controller_id() -> u32 { - use skyline::nn::hid::*; let min_controller_id = (0..8) .filter(|i| GetNpadStyleSet(i as *const _).flags != 0) .min() @@ -24,18 +24,14 @@ pub unsafe fn p1_controller_id() -> u32 { } pub unsafe fn handle_get_npad_state( - state: *mut skyline::nn::hid::NpadHandheldState, + state: *mut NpadHandheldState, controller_id: *const u32, ) { if *controller_id == p1_controller_id() { let mut delayed_states = P1_DELAYED_NPAD_STATES.lock(); let actual_state = *state; - // if INPUT_RECORD == 1 { - // P1_NPAD_STATES[INPUT_RECORD_FRAME] = actual_state; - // } - - if delayed_states.len() < crate::common::MENU.input_delay as usize { + if delayed_states.len() < MENU.input_delay as usize { (*state).Buttons = 0; (*state).LStickX = 0; (*state).LStickY = 0; @@ -52,15 +48,28 @@ pub unsafe fn handle_get_npad_state( } delayed_states.push_front(actual_state); - delayed_states.truncate(crate::common::MENU.input_delay as usize); - } else { - // if INPUT_RECORD == 1 || INPUT_RECORD == 2 { - // (*state).Buttons = P1_NPAD_STATES[INPUT_RECORD_FRAME].Buttons; - // (*state).LStickX = P1_NPAD_STATES[INPUT_RECORD_FRAME].LStickX; - // (*state).LStickY = P1_NPAD_STATES[INPUT_RECORD_FRAME].LStickY; - // (*state).RStickX = P1_NPAD_STATES[INPUT_RECORD_FRAME].RStickX; - // (*state).RStickY = P1_NPAD_STATES[INPUT_RECORD_FRAME].RStickY; - // (*state).Flags = P1_NPAD_STATES[INPUT_RECORD_FRAME].Flags; - // } + delayed_states.truncate(MENU.input_delay as usize); } } + +#[macro_export] +macro_rules! create_nn_hid_hooks { + ( + $( + ($func:ident, $hook:ident) + ),* + ) => { + $( + #[allow(non_snake_case)] + #[skyline::hook(replace = $func)] + pub unsafe fn $hook( + state: *mut skyline::nn::hid::NpadHandheldState, + controller_id: *const u32, + ) { + original!()(state, controller_id); + input_delay::handle_get_npad_state(state, controller_id); + // input_record::handle_get_npad_state(state, controller_id); + } + )* + }; +} diff --git a/src/training/input_record.rs b/src/training/input_record.rs new file mode 100644 index 0000000..e512627 --- /dev/null +++ b/src/training/input_record.rs @@ -0,0 +1,87 @@ +use skyline::nn::hid::NpadHandheldState; +use smash::app::{BattleObjectModuleAccessor, lua_bind::WorkModule}; +use smash::lib::lua_const::*; +use crate::training::input_delay::p1_controller_id; + +pub static mut P1_NPAD_STATES: &mut [NpadHandheldState; 90] = &mut [{ + NpadHandheldState { + updateCount: 0, + Buttons: 0, + LStickX: 0, + LStickY: 0, + RStickX: 0, + RStickY: 0, + Flags: 0, + } +}; 90]; + +pub static mut INPUT_RECORD: InputRecordState = InputRecordState::None; +pub static mut INPUT_RECORD_FRAME: usize = 0; + +#[derive(PartialEq)] +pub enum InputRecordState { + None, + Record, + Playback, +} + +use InputRecordState::*; + +pub unsafe fn get_command_flag_cat(module_accessor: &mut BattleObjectModuleAccessor) { + let entry_id_int = + WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32; + + if entry_id_int == 0 { + if INPUT_RECORD == Record || INPUT_RECORD == Playback { + if INPUT_RECORD_FRAME >= P1_NPAD_STATES.len() - 1 { + if INPUT_RECORD == Record { + INPUT_RECORD = Playback; + } + INPUT_RECORD_FRAME = 0; + } else { + INPUT_RECORD_FRAME += 1; + } + } + } +} + +pub unsafe fn record() { + INPUT_RECORD = Record; + P1_NPAD_STATES.iter_mut().for_each(|state| { + *state = NpadHandheldState { + updateCount: 0, + Buttons: 0, + LStickX: 0, + LStickY: 0, + RStickX: 0, + RStickY: 0, + Flags: 0, + } + }); + INPUT_RECORD_FRAME = 0; +} + +pub unsafe fn playback() { + INPUT_RECORD = Playback; + INPUT_RECORD_FRAME = 0; +} + +pub unsafe fn handle_get_npad_state( + state: *mut NpadHandheldState, + controller_id: *const u32, +) { + if *controller_id == p1_controller_id() { + if INPUT_RECORD == Record { + P1_NPAD_STATES[INPUT_RECORD_FRAME] = *state; + } + } else { + if INPUT_RECORD == Record || INPUT_RECORD == Playback { + (*state).Buttons = P1_NPAD_STATES[INPUT_RECORD_FRAME].Buttons; + (*state).LStickX = P1_NPAD_STATES[INPUT_RECORD_FRAME].LStickX; + (*state).LStickY = P1_NPAD_STATES[INPUT_RECORD_FRAME].LStickY; + (*state).RStickX = P1_NPAD_STATES[INPUT_RECORD_FRAME].RStickX; + (*state).RStickY = P1_NPAD_STATES[INPUT_RECORD_FRAME].RStickY; + (*state).Flags = P1_NPAD_STATES[INPUT_RECORD_FRAME].Flags; + } + } +} \ No newline at end of file diff --git a/src/training/mod.rs b/src/training/mod.rs index df28814..288098c 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -16,7 +16,9 @@ mod character_specific; mod fast_fall; mod frame_counter; mod full_hop; +#[macro_use] mod input_delay; +mod input_record; mod ledge; mod mash; mod reset; @@ -61,10 +63,6 @@ pub unsafe fn handle_get_attack_air_kind( return ori; } - // bool replace; - // int kind = InputRecorder::get_attack_air_kind(module_accessor, replace); - // if (replace) return kind; - mash::get_attack_air_kind(module_accessor).unwrap_or(ori) } @@ -83,10 +81,6 @@ pub unsafe fn handle_get_command_flag_cat( return flag; } - // bool replace; - // int ret = InputRecorder::get_command_flag_cat(module_accessor, category, flag, replace); - // if (replace) return ret; - flag |= mash::get_command_flag_cat(module_accessor, category); once_per_frame_per_fighter(module_accessor, category); @@ -103,24 +97,7 @@ fn once_per_frame_per_fighter( } unsafe { - let entry_id_int = - WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32; - - if entry_id_int == 0 { - // if INPUT_RECORD == 1 || INPUT_RECORD == 2 { - // if INPUT_RECORD_FRAME >= P1_NPAD_STATES.len() - 1 { - // if INPUT_RECORD == 1 { - // INPUT_RECORD = 2; - // } - // INPUT_RECORD_FRAME = 0; - // } else { - // INPUT_RECORD_FRAME += 1; - // } - // } - } - } - - unsafe { + input_record::get_command_flag_cat(module_accessor); combo::get_command_flag_cat(module_accessor); hitbox_visualizer::get_command_flag_cat(module_accessor); save_states::save_states(module_accessor); @@ -296,46 +273,39 @@ extern "C" { #[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_16NpadFullKeyStateERKj"] pub fn GetNpadFullKeyState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32); + + #[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_11NpadGcStateERKj"] + pub fn GetNpadGcState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32); + + #[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_16NpadJoyDualStateERKj"] + pub fn GetNpadJoyDualState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32); + + #[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_16NpadJoyLeftStateERKj"] + pub fn GetNpadJoyLeftState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32); + + #[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_17NpadJoyRightStateERKj"] + pub fn GetNpadJoyRightState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32); } -pub static mut P1_NPAD_STATES: &mut [skyline::nn::hid::NpadHandheldState; 90] = &mut [{ - skyline::nn::hid::NpadHandheldState { - updateCount: 0, - Buttons: 0, - LStickX: 0, - LStickY: 0, - RStickX: 0, - RStickY: 0, - Flags: 0, - } -}; 90]; - -pub static mut INPUT_RECORD: u32 = 0; -pub static mut INPUT_RECORD_FRAME: usize = 0; - -#[skyline::hook(replace = GetNpadHandheldState)] -pub unsafe fn handle_GetNpadHandheldState( - state: *mut skyline::nn::hid::NpadHandheldState, - controller_id: *const u32, -) { - original!()(state, controller_id); - input_delay::handle_get_npad_state(state, controller_id); -} - -#[skyline::hook(replace = GetNpadFullKeyState)] -pub unsafe fn handle_GetNpadFullKeyState( - state: *mut skyline::nn::hid::NpadHandheldState, - controller_id: *const u32, -) { - original!()(state, controller_id); - input_delay::handle_get_npad_state(state, controller_id); -} +create_nn_hid_hooks!( + (GetNpadHandheldState, handle_get_npad_handheld_state), + (GetNpadFullKeyState, handle_get_npad_full_key_state), + (GetNpadGcState, handle_get_npad_gc_state), + (GetNpadJoyDualState, handle_get_joy_dual_state), + (GetNpadJoyLeftState, handle_get_joy_left_state), + (GetNpadJoyRightState, handle_get_joy_right_state)); pub fn training_mods() { println!("[Training Modpack] Applying training mods."); // Input Recording/Delay - skyline::install_hooks!(handle_GetNpadHandheldState, handle_GetNpadFullKeyState); + skyline::install_hooks!( + handle_get_npad_handheld_state, + handle_get_npad_full_key_state, + handle_get_npad_gc_state, + handle_get_joy_dual_state, + handle_get_joy_left_state, + handle_get_joy_right_state); unsafe { LookupSymbol( diff --git a/src/training/save_states.rs b/src/training/save_states.rs index 2745e73..f61eaeb 100644 --- a/src/training/save_states.rs +++ b/src/training/save_states.rs @@ -86,8 +86,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) SAVE_STATE_CPU.state = KillPlayer; } - super::INPUT_RECORD = 2; - super::INPUT_RECORD_FRAME = 0; + // crate::training::input_record::playback(); reset::on_reset(); return; @@ -196,19 +195,7 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor) SAVE_STATE_PLAYER.state = Save; SAVE_STATE_CPU.state = Save; - super::INPUT_RECORD = 1; - super::P1_NPAD_STATES.iter_mut().for_each(|state| { - *state = skyline::nn::hid::NpadHandheldState { - updateCount: 0, - Buttons: 0, - LStickX: 0, - LStickY: 0, - RStickX: 0, - RStickY: 0, - Flags: 0, - } - }); - super::INPUT_RECORD_FRAME = 0; + // crate::training::input_record::record(); } if save_state.state == Save {