mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-03-14 02:16:10 +00:00
Params hook refactor, basis for input delay (#162)
* use Params hook * Add input delay
This commit is contained in:
parent
1885258c4e
commit
7b362c8330
10 changed files with 185 additions and 85 deletions
11
Cargo.toml
11
Cargo.toml
|
@ -8,11 +8,13 @@ edition = "2018"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
||||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" }
|
||||
# skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" }
|
||||
# skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git" }
|
||||
bitflags = "1.2.1"
|
||||
# skyline = { path = "../../../../src/skyline-rs" }
|
||||
# skyline_smash = { path = "../../../../src/skyline-smash" }
|
||||
parking_lot = { version = "0.11.0", features = ["nightly"] }
|
||||
lazy_static = "1.4.0"
|
||||
skyline = { path = "../../../../src/skyline-rs" }
|
||||
skyline_smash = { path = "../../../../src/skyline-smash" }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
@ -25,5 +27,6 @@ lto = true
|
|||
titleid = "01006A800016E000"
|
||||
plugin-dependencies = [
|
||||
{ name = "libnro_hook.nro", url = "https://github.com/ultimate-research/nro-hook-plugin/releases/download/v0.1.1/libnro_hook.nro" },
|
||||
{ name = "libparam_hook.nro", url = "https://github.com/ultimate-research/params-hook-plugin/releases/download/v0.1/libparam_hook.nro" },
|
||||
]
|
||||
|
||||
|
|
|
@ -28,6 +28,15 @@ Use this to practice optimal
|
|||
aerial heights and specific
|
||||
safe hitboxes.)"""";
|
||||
|
||||
// Input delay
|
||||
const std::vector<std::string> input_delay_items{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
|
||||
const std::string input_delay_help = R""""(
|
||||
In frames.
|
||||
|
||||
Emulate input delay
|
||||
to practice in a online
|
||||
environment.)"""";
|
||||
|
||||
// Side Taunt
|
||||
|
||||
// DI / Left Stick
|
||||
|
|
|
@ -32,6 +32,7 @@ static struct TrainingModpackMenu
|
|||
BoolFlags FALLING_AERIALS = BoolFlags::None;
|
||||
DelayFlags AERIAL_DELAY = DelayFlags::None;
|
||||
BoolFlags FULL_HOP = BoolFlags::None;
|
||||
int INPUT_DELAY = 0;
|
||||
} menu;
|
||||
|
||||
static struct TrainingModpackMenu defaultMenu = menu;
|
||||
|
@ -398,6 +399,11 @@ tsl::elm::Element* GuiMain::createUI()
|
|||
saveStateItem->setHelpListener([](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
||||
list->addItem(saveStateItem);
|
||||
|
||||
ValueListItem* inputDelayItem =
|
||||
new ValueListItem("Input Delay", input_delay_items, &menu.INPUT_DELAY, "inputDelay", input_delay_help);
|
||||
list->addItem(inputDelayItem);
|
||||
valueListItems.push_back(inputDelayItem);
|
||||
|
||||
ClickableListItem* resetMenuItem =
|
||||
new ClickableListItem("Reset Menu", empty_items, nullptr, "resetMenu", 0, "Reset Menu", reset_menu_help);
|
||||
resetMenuItem->setClickListener([](std::vector<std::string> values,
|
||||
|
|
|
@ -337,6 +337,7 @@ pub struct TrainingModpackMenu {
|
|||
pub falling_aerials: BoolFlag,
|
||||
pub aerial_delay: Delay,
|
||||
pub full_hop: BoolFlag,
|
||||
pub input_delay: i32,
|
||||
}
|
||||
|
||||
// Fighter Ids
|
||||
|
|
|
@ -28,6 +28,7 @@ pub static mut MENU_STRUCT: consts::TrainingModpackMenu = consts::TrainingModpac
|
|||
falling_aerials: BoolFlag::empty(),
|
||||
aerial_delay: Delay::empty(),
|
||||
full_hop: BoolFlag::empty(),
|
||||
input_delay: 0,
|
||||
};
|
||||
|
||||
pub static mut MENU: &'static mut consts::TrainingModpackMenu = unsafe { &mut MENU_STRUCT };
|
||||
|
|
|
@ -17,6 +17,10 @@ use skyline::libc::{c_void, fclose, fopen, fwrite, mkdir};
|
|||
use skyline::nro::{self, NroInfo};
|
||||
|
||||
fn nro_main(nro: &NroInfo<'_>) {
|
||||
if nro.module.isLoaded {
|
||||
return;
|
||||
}
|
||||
|
||||
match nro.name {
|
||||
"common" => {
|
||||
skyline::install_hooks!(
|
||||
|
|
66
src/training/input_delay.rs
Normal file
66
src/training/input_delay.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use skyline::nn::hid::NpadHandheldState;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
lazy_static! {
|
||||
static ref P1_DELAYED_NPAD_STATES: Mutex<VecDeque<NpadHandheldState>> =
|
||||
Mutex::new(VecDeque::new());
|
||||
}
|
||||
|
||||
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()
|
||||
.unwrap_or(0);
|
||||
|
||||
let handheld_id = 0x20;
|
||||
if GetNpadStyleSet(&handheld_id as *const _).flags != 0 {
|
||||
handheld_id
|
||||
} else {
|
||||
min_controller_id
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn handle_get_npad_state(
|
||||
state: *mut skyline::nn::hid::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 {
|
||||
(*state).Buttons = 0;
|
||||
(*state).LStickX = 0;
|
||||
(*state).LStickY = 0;
|
||||
(*state).RStickX = 0;
|
||||
(*state).RStickY = 0;
|
||||
(*state).Flags = 0;
|
||||
} else if let Some(delayed_state) = delayed_states.back() {
|
||||
(*state).Buttons = delayed_state.Buttons;
|
||||
(*state).LStickX = delayed_state.LStickX;
|
||||
(*state).LStickY = delayed_state.LStickY;
|
||||
(*state).RStickX = delayed_state.RStickX;
|
||||
(*state).RStickY = delayed_state.RStickY;
|
||||
(*state).Flags = delayed_state.Flags;
|
||||
}
|
||||
|
||||
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;
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ mod character_specific;
|
|||
mod fast_fall;
|
||||
mod frame_counter;
|
||||
mod full_hop;
|
||||
mod input_delay;
|
||||
mod ledge;
|
||||
mod mash;
|
||||
mod reset;
|
||||
|
@ -74,7 +75,9 @@ pub unsafe fn handle_get_command_flag_cat(
|
|||
) -> i32 {
|
||||
let mut flag = original!()(module_accessor, category);
|
||||
|
||||
shield::param_installer();
|
||||
if category == FIGHTER_PAD_COMMAND_CATEGORY1 {
|
||||
shield::param_installer();
|
||||
}
|
||||
|
||||
if !is_training_mode() {
|
||||
return flag;
|
||||
|
@ -99,6 +102,24 @@ fn once_per_frame_per_fighter(
|
|||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
combo::get_command_flag_cat(module_accessor);
|
||||
hitbox_visualizer::get_command_flag_cat(module_accessor);
|
||||
|
@ -172,42 +193,6 @@ pub unsafe fn get_stick_y(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
air_dodge_direction::mod_get_stick_y(module_accessor).unwrap_or(ori)
|
||||
}
|
||||
|
||||
// int get_pad_flag(u64 module_accessor) {
|
||||
// u64 control_module = load_module(module_accessor, 0x48);
|
||||
// int (*get_pad_flag)(u64) = (int (*)(u64)) load_module_impl(control_module, 0x348);
|
||||
// int pad_flag = get_pad_flag(control_module);
|
||||
|
||||
// bool replace;
|
||||
// int ret = InputRecorder::get_pad_flag(module_accessor, replace);
|
||||
// if (replace) return ret;
|
||||
|
||||
// return pad_flag;
|
||||
// }
|
||||
|
||||
// float get_stick_x_replace(u64 module_accessor) {
|
||||
// u64 control_module = load_module(module_accessor, 0x48);
|
||||
// float (*get_stick_x)(u64) = (float (*)(u64)) load_module_impl(control_module, 0x178);
|
||||
// float stick_x = get_stick_x(control_module);
|
||||
|
||||
// bool replace;
|
||||
// float ret = InputRecorder::get_stick_x(module_accessor, replace);
|
||||
// if (replace) return ret;
|
||||
|
||||
// return stick_x;
|
||||
// }
|
||||
|
||||
// float get_attack_air_stick_x_replace(u64 module_accessor) {
|
||||
// u64 control_module = load_module(module_accessor, 0x48);
|
||||
// float (*get_attack_air_stick_x)(u64) = (float (*)(u64)) load_module_impl(control_module, 0x188);
|
||||
// float stick_y = get_attack_air_stick_x(control_module);
|
||||
|
||||
// bool replace;
|
||||
// float ret = InputRecorder::get_attack_air_stick_x(module_accessor, replace);
|
||||
// if (replace) return ret;
|
||||
|
||||
// return stick_y;
|
||||
// }
|
||||
|
||||
#[skyline::hook(replace = ControlModule::check_button_on)]
|
||||
pub unsafe fn handle_check_button_on(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
|
@ -297,35 +282,61 @@ pub unsafe fn handle_set_dead_rumble(lua_state: u64) -> u64 {
|
|||
|
||||
pub static mut COMMON_PARAMS: *mut CommonParams = 0 as *mut _;
|
||||
|
||||
// 8.1.0 Offset
|
||||
static mut LOAD_PRC_FILE_OFFSET: usize = 0x34369d0;
|
||||
|
||||
static LOAD_PRC_FILE_SEARCH_CODE: &[u8] = &[
|
||||
0xff, 0xc3, 0x01, 0xd1, 0xff, 0xdf, 0x02, 0xa9, 0xf6, 0x57, 0x04, 0xa9, 0xf4, 0x4f, 0x05, 0xa9,
|
||||
0xfd, 0x7b, 0x06, 0xa9, 0xfd, 0x83, 0x01, 0x91, 0xf6, 0x5f, 0x00, 0x32, 0x88, 0x79, 0x00, 0xb0,
|
||||
0x08, 0xed, 0x0f, 0x91, 0xf3, 0x03, 0x00, 0xaa, 0xe8, 0x07, 0x00, 0xf9, 0xe8, 0x03, 0x00, 0x91,
|
||||
0x3f, 0x00, 0x16, 0x6b,
|
||||
];
|
||||
|
||||
#[skyline::hook(offset = LOAD_PRC_FILE_OFFSET)]
|
||||
unsafe fn load_once_common_params(common_obj: u64, table1_idx: u32) {
|
||||
let loaded_tables = smash::resource::LoadedTables::get_instance();
|
||||
let hash = loaded_tables.get_hash_from_t1_index(table1_idx).as_u64();
|
||||
|
||||
if hash == smash::phx::Hash40::new("fighter/common/param/common.prc").hash {
|
||||
COMMON_PARAMS = CommonParams::from_u64_mut(common_obj).unwrap() as *mut _;
|
||||
fn params_main(params_info: &ParamsInfo<'_>) {
|
||||
if let Ok(common) = params_info.get::<CommonParams>() {
|
||||
unsafe {
|
||||
COMMON_PARAMS = common as *mut _;
|
||||
}
|
||||
}
|
||||
original!()(common_obj, table1_idx)
|
||||
}
|
||||
|
||||
fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||
haystack
|
||||
.windows(needle.len())
|
||||
.position(|window| window == needle)
|
||||
extern "C" {
|
||||
#[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_17NpadHandheldStateERKj"]
|
||||
pub fn GetNpadHandheldState(arg1: *mut skyline::nn::hid::NpadHandheldState, arg2: *const u32);
|
||||
|
||||
#[link_name = "\u{1}_ZN2nn3hid12GetNpadStateEPNS0_16NpadFullKeyStateERKj"]
|
||||
pub fn GetNpadFullKeyState(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);
|
||||
}
|
||||
|
||||
pub fn training_mods() {
|
||||
println!("[Training Modpack] Applying training mods.");
|
||||
|
||||
// Input Recording/Delay
|
||||
skyline::install_hooks!(handle_GetNpadHandheldState, handle_GetNpadFullKeyState);
|
||||
|
||||
unsafe {
|
||||
LookupSymbol(
|
||||
&mut FIGHTER_MANAGER_ADDR,
|
||||
|
@ -341,16 +352,7 @@ pub fn training_mods() {
|
|||
.as_ptr(),
|
||||
);
|
||||
|
||||
use skyline::hooks::{getRegionAddress, Region};
|
||||
|
||||
let text_ptr = getRegionAddress(Region::Text) as *const u8;
|
||||
let text_size = (getRegionAddress(Region::Rodata) as usize) - (text_ptr as usize);
|
||||
let text = std::slice::from_raw_parts(text_ptr, text_size);
|
||||
if let Some(offset) = find_subsequence(text, LOAD_PRC_FILE_SEARCH_CODE) {
|
||||
LOAD_PRC_FILE_OFFSET = offset;
|
||||
} else {
|
||||
println!("Error: no offset found for function 'load_prc_file'. Defaulting to 8.1.0 offset. This likely won't work.");
|
||||
}
|
||||
smash::params::add_hook(params_main).unwrap();
|
||||
}
|
||||
|
||||
skyline::install_hooks!(
|
||||
|
@ -377,8 +379,6 @@ pub fn training_mods() {
|
|||
handle_is_enable_transition_term,
|
||||
// SDI
|
||||
crate::training::sdi::check_hit_stop_delay_command,
|
||||
// Generic params
|
||||
load_once_common_params
|
||||
);
|
||||
|
||||
combo::init();
|
||||
|
@ -386,12 +386,4 @@ pub fn training_mods() {
|
|||
fast_fall::init();
|
||||
mash::init();
|
||||
ledge::init();
|
||||
|
||||
// // Input recorder
|
||||
// SaltySD_function_replace_sym(
|
||||
// "_ZN3app8lua_bind31ControlModule__get_stick_x_implEPNS_26BattleObjectModuleAccessorE",
|
||||
// (u64)&ControlModule::get_stick_x_replace);
|
||||
// SaltySD_function_replace_sym(
|
||||
// "_ZN3app8lua_bind31ControlModule__get_attack_air_stick_x_implEPNS_26BattleObjectModuleAccessorE",
|
||||
// (u64)&ControlModule::get_attack_air_stick_x_replace);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,10 @@ pub unsafe fn save_states(module_accessor: &mut app::BattleObjectModuleAccessor)
|
|||
SAVE_STATE_PLAYER.state = KillPlayer;
|
||||
SAVE_STATE_CPU.state = KillPlayer;
|
||||
}
|
||||
|
||||
super::INPUT_RECORD = 2;
|
||||
super::INPUT_RECORD_FRAME = 0;
|
||||
|
||||
reset::on_reset();
|
||||
return;
|
||||
}
|
||||
|
@ -191,6 +195,20 @@ 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;
|
||||
}
|
||||
|
||||
if save_state.state == Save {
|
||||
|
|
|
@ -120,7 +120,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule
|
|||
]
|
||||
.contains(&status)
|
||||
{
|
||||
let status = match MENU.miss_tech_state.get_random() {
|
||||
let status: i32 = match MENU.miss_tech_state.get_random() {
|
||||
MissTechFlags::GETUP => *FIGHTER_STATUS_KIND_DOWN_STAND,
|
||||
MissTechFlags::ATTACK => *FIGHTER_STATUS_KIND_DOWN_STAND_ATTACK,
|
||||
MissTechFlags::ROLL_F => {
|
||||
|
@ -131,7 +131,7 @@ pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModule
|
|||
MISS_TECH_ROLL_DIRECTION = Direction::OUT; // = Away
|
||||
*FIGHTER_STATUS_KIND_DOWN_STAND_FB
|
||||
}
|
||||
_ => *FIGHTER_STATUS_KIND_DOWN_STAND,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
StatusModule::change_status_request_from_script(module_accessor, status, false);
|
||||
|
|
Loading…
Add table
Reference in a new issue