1
0
Fork 0
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:
jugeeya 2020-09-14 13:43:06 -07:00 committed by GitHub
parent 1885258c4e
commit 7b362c8330
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 185 additions and 85 deletions

View file

@ -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" },
]

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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 };

View file

@ -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!(

View 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;
// }
}
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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);