1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2024-11-20 00:46:34 +00:00

Increase Resilience to Game Updates by Dynamically Finding Offsets (#661)

* Search for offsets instead of using static offsets

* Collect the rest of the offsets, still need to convert into needle searches

* Finish writing offset search code

* Run rustfmt

* Fix build error

* Fix clippy warnings

* Add additional bytes and use symbols to prevent false-positives

* Replace additional offsets with symbols

* Change add_damage from symbol back to offset
This commit is contained in:
asimon-1 2024-01-10 17:58:27 -05:00 committed by GitHub
parent b2ef9b85a7
commit bf94573193
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 497 additions and 166 deletions

View file

@ -5,6 +5,7 @@ use smash::lua2cpp::L2CFighterCommon;
pub use crate::common::consts::MENU; pub use crate::common::consts::MENU;
use crate::common::consts::*; use crate::common::consts::*;
use crate::common::offsets::OFFSET_GET_BATTLE_OBJECT_FROM_ID;
use crate::training::character_specific::ptrainer; use crate::training::character_specific::ptrainer;
pub mod button_config; pub mod button_config;
@ -14,6 +15,7 @@ pub mod dialog;
pub mod events; pub mod events;
pub mod input; pub mod input;
pub mod menu; pub mod menu;
pub mod offsets;
pub mod raygun_printer; pub mod raygun_printer;
pub mod release; pub mod release;
@ -34,7 +36,7 @@ pub fn is_training_mode() -> bool {
true true
} }
#[skyline::from_offset(0x3ac540)] #[skyline::from_offset(*OFFSET_GET_BATTLE_OBJECT_FROM_ID as isize)]
pub fn get_battle_object_from_id(battle_object_id: u32) -> *mut app::BattleObject; pub fn get_battle_object_from_id(battle_object_id: u32) -> *mut app::BattleObject;
pub fn get_category(module_accessor: &app::BattleObjectModuleAccessor) -> i32 { pub fn get_category(module_accessor: &app::BattleObjectModuleAccessor) -> i32 {

347
src/common/offsets.rs Normal file
View file

@ -0,0 +1,347 @@
// TODO!(Do all these need to be referenced by offset? Or do some of them have symbols?)
#![cfg_attr(rustfmt, rustfmt_skip)] // We want the assembly needles to stay in lines of four bytes each
use crate::logging::*;
use lazy_static::lazy_static;
// Stolen from HDR who stole it from Arcropolis
// https://github.com/HDR-Development/HewDraw-Remix/blob/dev/dynamic/src/util.rs
pub fn byte_search<T: Eq>(needle: &[T]) -> Option<usize> {
let text = unsafe {
let start = skyline::hooks::getRegionAddress(skyline::hooks::Region::Text) as *const T;
let end = skyline::hooks::getRegionAddress(skyline::hooks::Region::Rodata) as *const T;
let length = end.offset_from(start) as usize;
std::slice::from_raw_parts(start, length)
};
text.windows(needle.len())
.position(|window| window == needle)
}
// Wrapper around byte_search() with some additional logging
fn find_offset(name: &str, needle: &[u8]) -> Option<usize> {
info!("Searching for {}", name);
let offset_opt = byte_search(needle);
match offset_opt {
Some(offset) => {
info!("Found offset for {} at {:#x}", name, offset);
Some(offset)
}
None => {
error!("Cound not find offset for {}", name);
None
}
}
}
macro_rules! impl_offset {
($fn_name:ident) => {
paste::paste! {
lazy_static! {
pub static ref [<OFFSET_ $fn_name>]: usize = find_offset(stringify!($fn_name), [<NEEDLE_ $fn_name>]).expect(stringify!(Failed to find offset for $fn_name));
}
}
}
}
// To add a new offset, you need to define a NEEDLE_ static first with the
// bytecode at that offset.
//
// Example:
// OFFSET_GET_BATTLE_OBJECT_FROM_ID gets defined by the NEEDLE_GET_BATTLE_OBJECT_FROM_ID
// bytecode and the impl_offset! macro with the argument GET_BATTLE_OBJECT_FROM_ID
//
// Recommended to use the first 8 instructions (32 bytes), unless the function is shorter
// OFFSET_GET_BATTLE_OBJECT_FROM_ID = 0x3ac540
static NEEDLE_GET_BATTLE_OBJECT_FROM_ID: &[u8] = &[
0xff, 0x03, 0x06, 0xd1,
0xee, 0x73, 0x00, 0xfd,
0xed, 0x33, 0x0f, 0x6d,
0xeb, 0x2b, 0x10, 0x6d,
0xe9, 0x23, 0x11, 0x6d,
0xfc, 0x6f, 0x12, 0xa9,
0xfa, 0x67, 0x13, 0xa9,
0xf8, 0x5f, 0x14, 0xa9,
];
impl_offset!(GET_BATTLE_OBJECT_FROM_ID);
// OFFSET_COPY_SETUP = 0xba0e60
static NEEDLE_COPY_SETUP: &[u8] = &[
0xe8, 0x0f, 0x19, 0xfc,
0xfc, 0x6f, 0x01, 0xa9,
0xfa, 0x67, 0x02, 0xa9,
0xf8, 0x5f, 0x03, 0xa9,
0xf6, 0x57, 0x04, 0xa9,
0xf4, 0x4f, 0x05, 0xa9,
0xfd, 0x7b, 0x06, 0xa9,
0xfd, 0x83, 0x01, 0x91,
];
impl_offset!(COPY_SETUP);
// OFFSET_IS_VISIBLE_BACKSHIELD = 0x1655400
static NEEDLE_IS_VISIBLE_BACKSHIELD: &[u8] = &[
0xfd, 0x7b, 0xbf, 0xa9,
0xfd, 0x03, 0x00, 0x91,
0x00, 0x28, 0x40, 0xf9,
0x08, 0x00, 0x40, 0xf9,
0x08, 0x85, 0x40, 0xf9,
0xa1, 0x0f, 0x80, 0x52,
0x01, 0x00, 0xa4, 0x72,
0x00, 0x01, 0x3f, 0xd6,
];
impl_offset!(IS_VISIBLE_BACKSHIELD);
// OFFSET_SET_CPU_CONTROLS = 0x2da180
static NEEDLE_SET_CPU_CONTROLS: &[u8] = &[
0xff, 0x03, 0x06, 0xd1,
0xee, 0x73, 0x00, 0xfd,
0xed, 0x33, 0x0f, 0x6d,
0xeb, 0x2b, 0x10, 0x6d,
0xe9, 0x23, 0x11, 0x6d,
0xfc, 0x6f, 0x12, 0xa9,
0xfa, 0x67, 0x13, 0xa9,
0xf8, 0x5f, 0x14, 0xa9,
];
impl_offset!(SET_CPU_CONTROLS);
// OFFSET_ADD_DAMAGE = 0x3ff9a0
static NEEDLE_ADD_DAMAGE: &[u8] = &[
0x08, 0x20, 0x20, 0x1e,
0x8d, 0x00, 0x00, 0x54,
0x08, 0x14, 0x4e, 0x39,
0x48, 0x00, 0x00, 0x34,
0xc0, 0x03, 0x5f, 0xd6,
];
impl_offset!(ADD_DAMAGE);
// OFFSET_CHANGE_ACTIVE_CAMERA = 0x4ee460
static NEEDLE_CHANGE_ACTIVE_CAMERA: &[u8] = &[
0xff, 0x03, 0x02, 0xd1,
0xf8, 0x5f, 0x04, 0xa9,
0xf6, 0x57, 0x05, 0xa9,
0xf4, 0x4f, 0x06, 0xa9,
0xfd, 0x7b, 0x07, 0xa9,
0xfd, 0xc3, 0x01, 0x91,
0x08, 0x04, 0x40, 0xb9,
0x1f, 0x01, 0x01, 0x6b,
];
impl_offset!(CHANGE_ACTIVE_CAMERA);
// OFFSET_SET_TRAINING_FIXED_CAMERA_VALUES = 0x3157bb0
static NEEDLE_SET_TRAINING_FIXED_CAMERA_VALUES: &[u8] = &[
0x01, 0xe4, 0x00, 0x2f,
0x20, 0x00, 0xc0, 0x3d,
0x22, 0x1c, 0xa1, 0x4e,
0x02, 0x44, 0x04, 0x6e,
0xe8, 0x0a, 0x01, 0xf0,
0x08, 0x81, 0x47, 0xf9,
0x08, 0x01, 0x40, 0xf9,
0x40, 0x04, 0x18, 0x6e,
0x00, 0xf5, 0x82, 0x3d,
];
impl_offset!(SET_TRAINING_FIXED_CAMERA_VALUES);
// OFFSET_DRAW = 0x4b620
static NEEDLE_DRAW: &[u8] = &[
0x08, 0x0c, 0x40, 0xf9,
0xc8, 0x03, 0x00, 0xb4,
0xff, 0x83, 0x01, 0xd1,
0xf5, 0x1b, 0x00, 0xf9,
0xf4, 0x4f, 0x04, 0xa9,
0xfd, 0x7b, 0x05, 0xa9,
0xfd, 0x43, 0x01, 0x91,
0xf4, 0x03, 0x00, 0xaa,
];
impl_offset!(DRAW);
// OFFSET_CLOUD_ADD_LIMIT = 0x8dc140
static NEEDLE_CLOUD_ADD_LIMIT: &[u8] = &[
0xff, 0x03, 0x03, 0xd1,
0xe9, 0x23, 0x05, 0x6d,
0xfc, 0x6f, 0x06, 0xa9,
0xfa, 0x67, 0x07, 0xa9,
0xf8, 0x5f, 0x08, 0xa9,
0xf6, 0x57, 0x09, 0xa9,
0xf4, 0x4f, 0x0a, 0xa9,
0xfd, 0x7b, 0x0b, 0xa9,
0xfd, 0xc3, 0x02, 0x91,
0x13, 0x28, 0x40, 0xf9,
0x68, 0x02, 0x40, 0xf9,
0x08, 0x85, 0x40, 0xf9,
];
impl_offset!(CLOUD_ADD_LIMIT);
// IMPORTANT! Because this offset is so close to OFFSET_STALE and
// because we are modifying inline instead of hooking the whole function,
// this hook has to be initialized first! Otherwise the search will fail.
// OFFSET_STALE_MENU = 0x13e88a0
static NEEDLE_STALE_MENU: &[u8] = &[
0xdf, 0x82, 0x2d, 0x39,
0x93, 0x40, 0x8e, 0x94,
0x00, 0x1d, 0xa8, 0x4e,
0xc0, 0xa2, 0x06, 0x91,
0xdf, 0x22, 0x2f, 0x39,
0xff, 0x43, 0x8e, 0x94,
0xca, 0x82, 0x6d, 0x39,
0xe8, 0x77, 0x01, 0x90,
0x08, 0x6d, 0x3c, 0x91,
];
impl_offset!(STALE_MENU);
// IMPORTANT! See above comment for STALE_MENU
// OFFSET_STALE = 0x13e88a4
static NEEDLE_STALE: &[u8] = &[
0x93, 0x40, 0x8e, 0x94,
0x00, 0x1d, 0xa8, 0x4e,
0xc0, 0xa2, 0x06, 0x91,
0xdf, 0x22, 0x2f, 0x39,
];
impl_offset!(STALE);
// todo!(Can we remove this and replace with SoundModule::play_se()?)
// OFFSET_PLAY_SE = 0x4cf6a0
static NEEDLE_PLAY_SE: &[u8] = &[
0xa8, 0x00, 0x00, 0x12,
0x9f, 0x00, 0x00, 0x72,
0xe9, 0x03, 0x1e, 0x32,
0x24, 0x11, 0x88, 0x1a,
0x42, 0x00, 0x00, 0x12,
0x63, 0x00, 0x00, 0x12,
0xe5, 0x03, 0x06, 0x2a,
];
impl_offset!(PLAY_SE);
// OFFSET_CAN_FUTTOBI_BACK = 0x260f950
static NEEDLE_CAN_FUTTOBI_BACK: &[u8] = &[
0x00, 0x07, 0x00, 0xb4,
0x09, 0x04, 0x40, 0xf9,
0x28, 0x01, 0x40, 0x39,
0x1f, 0x31, 0x00, 0x71,
0x41, 0x04, 0x00, 0x54,
0x28, 0x11, 0x40, 0xb8,
0x0a, 0x05, 0x00, 0x71,
0xeb, 0x03, 0x00, 0x54,
0x0d, 0x00, 0x40, 0xf9,
0x28, 0x51, 0x80, 0xb8,
0x8e, 0x7b, 0x94, 0xd2,
0x8e, 0x0d, 0xb7, 0xf2,
];
impl_offset!(CAN_FUTTOBI_BACK);
// OFFSET_REUSED_UI = 0x68cd80
static NEEDLE_REUSED_UI: &[u8] = &[
0xff, 0x43, 0x01, 0xd1,
0xf5, 0x13, 0x00, 0xf9,
0xf4, 0x4f, 0x03, 0xa9,
0xfd, 0x7b, 0x04, 0xa9,
0xfd, 0x03, 0x01, 0x91,
0x08, 0x00, 0x40, 0xb9,
0x1f, 0x21, 0x00, 0x71,
0x62, 0x06, 0x00, 0x54,
];
impl_offset!(REUSED_UI);
// OFFSET_OPCF = 0x6b7fdc
static NEEDLE_OPCF: &[u8] = &[
0x68, 0xb6, 0x40, 0xf9,
0x09, 0x81, 0x49, 0x39,
0x69, 0xe1, 0xff, 0x35,
0x08, 0x55, 0x41, 0x39,
0x28, 0xe1, 0x1f, 0x37,
0xe0, 0x03, 0x13, 0xaa,
0x63, 0x88, 0xf0, 0x97,
0xe9, 0x23, 0x43, 0x6d,
];
impl_offset!(OPCF);
// OFFSET_FIM = 0x17504a0
static NEEDLE_FIM: &[u8] = &[
0xff, 0x03, 0x02, 0xd1,
0xf7, 0x23, 0x00, 0xf9,
0xf6, 0x57, 0x05, 0xa9,
0xf4, 0x4f, 0x06, 0xa9,
0xfd, 0x7b, 0x07, 0xa9,
0xfd, 0xc3, 0x01, 0x91,
0x3f, 0x04, 0x00, 0x31,
0xe0, 0x77, 0x00, 0x54,
];
impl_offset!(FIM);
// OFFSET_SSS_TRAINING = 0x184d1d8
static NEEDLE_SSS_TRAINING: &[u8] = &[
0x9f, 0xe3, 0x0b, 0x39,
0x88, 0xbf, 0x0b, 0x39,
0x56, 0x02, 0x00, 0x14,
0x00, 0x01, 0x00, 0xf9,
0xe8, 0x03, 0x00, 0x32,
];
impl_offset!(SSS_TRAINING);
// OFFSET_GENERATE_ARTICLE_FOR_TARGET = 0x3d40a0
static NEEDLE_GENERATE_ARTICLE_FOR_TARGET: &[u8] = &[
0xf4, 0x4f, 0xbe, 0xa9,
0xfd, 0x7b, 0x01, 0xa9,
0xfd, 0x43, 0x00, 0x91,
0xf3, 0x03, 0x03, 0x2a,
0x42, 0x00, 0x00, 0xb5,
0x02, 0x04, 0x40, 0xf9,
];
impl_offset!(GENERATE_ARTICLE_FOR_TARGET);
// OFFSET_KIRBY_OPFF = 0xb971b0
static NEEDLE_KIRBY_OPFF: &[u8] = &[
0xff, 0x43, 0x02, 0xd1,
0xfc, 0x6f, 0x03, 0xa9,
0xfa, 0x67, 0x04, 0xa9,
0xf8, 0x5f, 0x05, 0xa9,
0xf6, 0x57, 0x06, 0xa9,
0xf4, 0x4f, 0x07, 0xa9,
0xfd, 0x7b, 0x08, 0xa9,
0xfd, 0x03, 0x02, 0x91,
0x3a, 0x10, 0x40, 0xf9,
0x54, 0x2b, 0x40, 0xf9,
0x88, 0x02, 0x40, 0xf9,
0x08, 0x59, 0x40, 0xf9,
];
impl_offset!(KIRBY_OPFF);
// OFFSET_ACTIVATE_AUTONOMY = 0x34b5cf0
static NEEDLE_ACTIVATE_AUTONOMY: &[u8] = &[
0xf6, 0x57, 0xbd, 0xa9,
0xf4, 0x4f, 0x01, 0xa9,
0xfd, 0x7b, 0x02, 0xa9,
0xfd, 0x83, 0x00, 0x91,
0x28, 0x00, 0x40, 0xf9,
0x08, 0x89, 0x40, 0xf9,
0xd5, 0x00, 0x80, 0x52,
0x15, 0x00, 0xa4, 0x72,
];
impl_offset!(ACTIVATE_AUTONOMY);
// OFFSET_POKEMON_DECIDE = 0x34cdc64
static NEEDLE_POKEMON_DECIDE: &[u8] = &[
0x28, 0x69, 0x2b, 0x38,
0x48, 0x26, 0x8b, 0x52,
0x2a, 0x69, 0x28, 0x38,
0x88, 0x12, 0x40, 0xf9,
0x49, 0x01, 0x80, 0x52,
0x14, 0x29, 0x40, 0xf9,
0xe9, 0x0b, 0x00, 0xb9,
0x29, 0xdf, 0x00, 0xb0,
];
impl_offset!(POKEMON_DECIDE);
// OFFSET_LAYOUT_ARC_MALLOC = 0x37730d4
static NEEDLE_LAYOUT_ARC_MALLOC: &[u8] = &[
0xe3, 0xe6, 0x06, 0x94,
0xa0, 0x05, 0x00, 0xb4,
0xe1, 0x03, 0x15, 0xaa,
0xe2, 0x03, 0x17, 0xaa,
0xc0, 0xb6, 0x00, 0xf9,
0x72, 0x2e, 0x09, 0x94,
0xc1, 0xb6, 0x40, 0xf9,
0xc2, 0x57, 0x00, 0xb0,
];
impl_offset!(LAYOUT_ARC_MALLOC);

View file

@ -7,6 +7,7 @@ use smash::lib::lua_const::*;
use crate::common::consts::*; use crate::common::consts::*;
use crate::common::*; use crate::common::*;
use crate::offsets::OFFSET_GENERATE_ARTICLE_FOR_TARGET;
use crate::training::mash; use crate::training::mash;
pub struct CharItem { pub struct CharItem {
@ -509,9 +510,7 @@ daikon_replace!(DAISY, daisy, 2);
daikon_replace!(DAISY, daisy, 1); daikon_replace!(DAISY, daisy, 1);
// GenerateArticleForTarget for Peach/Diddy(/Link?) item creation // GenerateArticleForTarget for Peach/Diddy(/Link?) item creation
static GAFT_OFFSET: usize = 0x03d40a0; #[skyline::hook(offset = *OFFSET_GENERATE_ARTICLE_FOR_TARGET)]
#[skyline::hook(offset = GAFT_OFFSET)]
pub unsafe fn handle_generate_article_for_target( pub unsafe fn handle_generate_article_for_target(
article_module_accessor: *mut BattleObjectModuleAccessor, article_module_accessor: *mut BattleObjectModuleAccessor,
int_1: i32, int_1: i32,

View file

@ -1,4 +1,5 @@
use crate::common::try_get_battle_object; use crate::common::try_get_battle_object;
use crate::offsets::OFFSET_KIRBY_OPFF;
use crate::training::charge::ChargeState; use crate::training::charge::ChargeState;
use crate::training::save_states; use crate::training::save_states;
use smash::app::{self, lua_bind::*, smashball::is_training_mode}; use smash::app::{self, lua_bind::*, smashball::is_training_mode};
@ -13,8 +14,7 @@ pub struct CopyModule {
} }
// Wait to set up copy ability variables until after CopyStart runs; // Wait to set up copy ability variables until after CopyStart runs;
static KIRBY_OPFF_OFFSET: usize = 0xb971b0; #[skyline::hook(offset = *OFFSET_KIRBY_OPFF)]
#[skyline::hook(offset = KIRBY_OPFF_OFFSET)]
pub unsafe fn handle_copy_start(param1: u64, kirby_fighter: *mut app::Fighter) -> u64 { pub unsafe fn handle_copy_start(param1: u64, kirby_fighter: *mut app::Fighter) -> u64 {
if !is_training_mode() || !save_states::is_loading() { if !is_training_mode() || !save_states::is_loading() {
return original!()(param1, kirby_fighter); return original!()(param1, kirby_fighter);

View file

@ -1,4 +1,5 @@
use crate::info; use crate::info;
use crate::offsets::OFFSET_ACTIVATE_AUTONOMY;
use smash::app::{self, lua_bind::*, smashball::is_training_mode}; use smash::app::{self, lua_bind::*, smashball::is_training_mode};
use smash::lib::lua_const::*; use smash::lib::lua_const::*;
@ -30,8 +31,7 @@ pub struct WeaponWorkModule {
} }
// Prevent Order Loss // Prevent Order Loss
static ACTIVATE_AUTONOMY_OFFSET: usize = 0x034b5cf0; #[skyline::hook(offset = *OFFSET_ACTIVATE_AUTONOMY)]
#[skyline::hook(offset = ACTIVATE_AUTONOMY_OFFSET)]
pub unsafe fn autonomy_handle(weapon: *mut app::Weapon, work_module: *mut WeaponWorkModule) { pub unsafe fn autonomy_handle(weapon: *mut app::Weapon, work_module: *mut WeaponWorkModule) {
if !is_training_mode() { if !is_training_mode() {
return original!()(weapon, work_module); return original!()(weapon, work_module);

View file

@ -1,3 +1,4 @@
use crate::offsets::OFFSET_POKEMON_DECIDE;
use crate::training::frame_counter; use crate::training::frame_counter;
use crate::training::save_states; use crate::training::save_states;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -138,9 +139,7 @@ pub unsafe fn handle_pokemon_sound_effect(hash: Hash40) -> Hash40 {
} }
// Choose which pokemon to switch to! // Choose which pokemon to switch to!
static POKEMON_DECIDE_OFFSET: usize = 0x34cdc64; #[skyline::hook(offset = *OFFSET_POKEMON_DECIDE, inline)]
#[skyline::hook(offset = POKEMON_DECIDE_OFFSET, inline)]
unsafe fn handle_pokemon_decide(ctx: &mut InlineCtx) { unsafe fn handle_pokemon_decide(ctx: &mut InlineCtx) {
if !is_training_mode() || !save_states::is_loading() { if !is_training_mode() || !save_states::is_loading() {
return; return;

View file

@ -1,4 +1,5 @@
use crate::common::consts::FighterId; use crate::common::consts::FighterId;
use crate::common::offsets::OFFSET_COPY_SETUP;
use crate::common::{get_module_accessor, try_get_battle_object}; use crate::common::{get_module_accessor, try_get_battle_object};
use crate::training::character_specific::{kirby, pikmin}; use crate::training::character_specific::{kirby, pikmin};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -7,7 +8,7 @@ use smash::lib::lua_const::*;
use smash::phx::{Hash40, Vector3f}; use smash::phx::{Hash40, Vector3f};
use std::ptr; use std::ptr;
#[skyline::from_offset(0xba0e60)] #[skyline::from_offset(*OFFSET_COPY_SETUP as isize)]
fn copy_setup( fn copy_setup(
module_accessor: *mut app::BattleObjectModuleAccessor, module_accessor: *mut app::BattleObjectModuleAccessor,
int: i32, int: i32,

View file

@ -1,4 +1,5 @@
use skyline::nn::ui2d::ResColor; use skyline::nn::ui2d::ResColor;
use smash::app::BattleObjectModuleAccessor;
use training_mod_consts::OnOff; use training_mod_consts::OnOff;
use crate::common::consts::FighterId; use crate::common::consts::FighterId;
@ -17,12 +18,12 @@ static mut FRAME_ADVANTAGE_CHECK: bool = false;
static FRAME_COUNTER_INDEX: Lazy<usize> = static FRAME_COUNTER_INDEX: Lazy<usize> =
Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame)); Lazy::new(|| frame_counter::register_counter(frame_counter::FrameCounterType::InGame));
unsafe fn _was_in_hitstun(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool { unsafe fn _was_in_hitstun(module_accessor: *mut BattleObjectModuleAccessor) -> bool {
let prev_status = StatusModule::prev_status_kind(module_accessor, 0); let prev_status = StatusModule::prev_status_kind(module_accessor, 0);
(*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&prev_status) (*FIGHTER_STATUS_KIND_DAMAGE..*FIGHTER_STATUS_KIND_DAMAGE_FALL).contains(&prev_status)
} }
unsafe fn was_in_shieldstun(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool { unsafe fn was_in_shieldstun(module_accessor: *mut BattleObjectModuleAccessor) -> bool {
let prev_status = StatusModule::prev_status_kind(module_accessor, 0); let prev_status = StatusModule::prev_status_kind(module_accessor, 0);
prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE
} }
@ -38,7 +39,7 @@ macro_rules! actionable_statuses {
}; };
} }
unsafe fn is_actionable(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool { unsafe fn is_actionable(module_accessor: *mut BattleObjectModuleAccessor) -> bool {
actionable_statuses!().iter().any(|actionable_transition| { actionable_statuses!().iter().any(|actionable_transition| {
WorkModule::is_enable_transition_term(module_accessor, **actionable_transition) WorkModule::is_enable_transition_term(module_accessor, **actionable_transition)
}) || CancelModule::is_enable_cancel(module_accessor) }) || CancelModule::is_enable_cancel(module_accessor)
@ -81,7 +82,7 @@ fn update_frame_advantage(new_frame_adv: i32) {
} }
pub unsafe fn is_enable_transition_term( pub unsafe fn is_enable_transition_term(
module_accessor: *mut app::BattleObjectModuleAccessor, module_accessor: *mut BattleObjectModuleAccessor,
transition_term: i32, transition_term: i32,
is: bool, is: bool,
) { ) {
@ -120,7 +121,7 @@ pub unsafe fn is_enable_transition_term(
} }
} }
pub unsafe fn get_command_flag_cat(module_accessor: &mut app::BattleObjectModuleAccessor) { 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); let entry_id_int = WorkModule::get_int(module_accessor, *FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
// do only once. // do only once.
if entry_id_int != (FighterId::Player as i32) { if entry_id_int != (FighterId::Player as i32) {

View file

@ -2,88 +2,98 @@
#![allow(unused_imports)] #![allow(unused_imports)]
#![cfg(debug_assertions)] #![cfg(debug_assertions)]
use crate::common::is_operation_cpu; use crate::common::is_operation_cpu;
use smash::app::{self, lua_bind::*, smashball::is_training_mode, utility}; use crate::common::offsets::OFFSET_IS_VISIBLE_BACKSHIELD;
use smash::app::{lua_bind::*, smashball::is_training_mode, utility, BattleObjectModuleAccessor};
use smash::lib::lua_const::*; use smash::lib::lua_const::*;
#[skyline::from_offset(0x1655400)] #[skyline::from_offset(*OFFSET_IS_VISIBLE_BACKSHIELD as isize)]
fn is_visible_backshield(module_accessor: *mut app::BattleObjectModuleAccessor) -> bool; fn is_visible_backshield(module_accessor: *mut BattleObjectModuleAccessor) -> bool;
#[repr(C)] #[repr(C)]
pub struct WorkModule2 { pub struct WorkModule2 {
vtable: u64, vtable: u64,
owner: &'static mut app::BattleObjectModuleAccessor, owner: &'static mut BattleObjectModuleAccessor,
} }
static ON_FLAG_OFFSET: usize = 0x4e4910; #[skyline::hook(replace = WorkModule::on_flag)]
#[skyline::hook(offset = ON_FLAG_OFFSET)] pub unsafe fn handle_on_flag(module_accessor: &mut BattleObjectModuleAccessor, address: i32) {
pub unsafe fn handle_on_flag(work_module: &mut WorkModule2, address: i32) {
if address == *WEAPON_PTRAINER_PTRAINER_INSTANCE_WORK_ID_FLAG_OUTFIELD_INVISIBLE if address == *WEAPON_PTRAINER_PTRAINER_INSTANCE_WORK_ID_FLAG_OUTFIELD_INVISIBLE
&& app::utility::get_kind(work_module.owner) != *FIGHTER_KIND_SHEIK && utility::get_kind(module_accessor) != *FIGHTER_KIND_SHEIK
{ {
is_visible_backshield(work_module.owner); is_visible_backshield(module_accessor);
} }
original!()(work_module, address); original!()(module_accessor, address);
} }
static SET_INT_OFFSET: usize = 0x4e4600; #[skyline::hook(replace = WorkModule::set_int)]
#[skyline::hook(offset = SET_INT_OFFSET)] pub unsafe fn handle_set_int(
pub unsafe fn handle_set_int(work_module: &mut WorkModule2, value: u32, address: i32) { module_accessor: &mut BattleObjectModuleAccessor,
value: u32,
address: i32,
) {
if !is_training_mode() { if !is_training_mode() {
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
if address == *WEAPON_PTRAINER_MBALL_INSTANCE_WORK_ID_INT_PLATE_EFF_ID if address == *WEAPON_PTRAINER_MBALL_INSTANCE_WORK_ID_INT_PLATE_EFF_ID
&& app::utility::get_kind(work_module.owner) == *WEAPON_KIND_PTRAINER_MBALL && utility::get_kind(module_accessor) == *WEAPON_KIND_PTRAINER_MBALL
{ {
is_visible_backshield(work_module.owner); is_visible_backshield(module_accessor);
} }
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
static SET_INT64_OFFSET: usize = 0x4e4680; #[skyline::hook(replace = WorkModule::set_int64)]
#[skyline::hook(offset = SET_INT64_OFFSET)] pub unsafe fn handle_set_int_64(
pub unsafe fn handle_set_int_64(work_module: &mut WorkModule2, value: u64, address: i32) { module_accessor: &mut BattleObjectModuleAccessor,
value: u64,
address: i32,
) {
if !is_training_mode() { if !is_training_mode() {
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
static SET_FLOAT_OFFSET: usize = 0x4e4420; #[skyline::hook(replace = WorkModule::set_float)]
#[skyline::hook(offset = SET_FLOAT_OFFSET)] pub unsafe fn handle_set_float(
pub unsafe fn handle_set_float(work_module: &mut WorkModule2, value: f32, address: i32) { module_accessor: &mut BattleObjectModuleAccessor,
value: f32,
address: i32,
) {
if !is_training_mode() { if !is_training_mode() {
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
if address == *FIGHTER_WIIFIT_INSTANCE_WORK_ID_FLOAT_SPECIAL_N_CHARGE_LEVEL_RATIO //*FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START if address == *FIGHTER_WIIFIT_INSTANCE_WORK_ID_FLOAT_SPECIAL_N_CHARGE_LEVEL_RATIO //*FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START
&& app::utility::get_kind(work_module.owner) == FIGHTER_KIND_KIRBY && utility::get_kind(module_accessor) == FIGHTER_KIND_KIRBY
{ {
is_visible_backshield(work_module.owner); is_visible_backshield(module_accessor);
} }
original!()(work_module, value, address); original!()(module_accessor, value, address);
} }
static IS_FLAG_OFFSET: usize = 0x4e48e0; #[skyline::hook(replace = WorkModule::is_flag)]
#[skyline::hook(offset = IS_FLAG_OFFSET)] pub unsafe fn handle_is_flag(
pub unsafe fn handle_is_flag(work_module: &mut WorkModule2, address: i32) -> bool { module_accessor: &mut BattleObjectModuleAccessor,
address: i32,
) -> bool {
if !is_training_mode() { if !is_training_mode() {
original!()(work_module, address); original!()(module_accessor, address);
} }
if address == *WEAPON_PTRAINER_PTRAINER_INSTANCE_WORK_ID_FLAG_ENABLE_CHANGE_POKEMON //*FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START if address == *WEAPON_PTRAINER_PTRAINER_INSTANCE_WORK_ID_FLAG_ENABLE_CHANGE_POKEMON //*FIGHTER_KIRBY_INSTANCE_WORK_ID_FLAG_COPY_ON_START
&& app::utility::get_kind(work_module.owner) != *FIGHTER_KIND_SHEIK && utility::get_kind(module_accessor) != *FIGHTER_KIND_SHEIK
&& original!()(work_module, address) && original!()(module_accessor, address)
{ {
is_visible_backshield(work_module.owner); is_visible_backshield(module_accessor);
} }
original!()(work_module, address) original!()(module_accessor, address)
} }
static GET_INT_OFFSET: usize = 0x4e45e0; #[skyline::hook(replace = WorkModule::get_int)]
#[skyline::hook(offset = GET_INT_OFFSET)] pub unsafe fn handle_get_int(module_accessor: &mut BattleObjectModuleAccessor, address: i32) {
pub unsafe fn handle_get_int(work_module: &mut WorkModule2, address: i32) {
if !is_training_mode() { if !is_training_mode() {
original!()(work_module, address); original!()(module_accessor, address);
} }
original!()(work_module, address); original!()(module_accessor, address);
} }
pub fn init() { pub fn init() {
@ -116,7 +126,7 @@ pub fn init() {
// ); // );
#[allow(clippy::too_many_arguments)] // This function has so many arguments so it's easy to quickly fill them in when debugging with the analyzer #[allow(clippy::too_many_arguments)] // This function has so many arguments so it's easy to quickly fill them in when debugging with the analyzer
pub fn print_fighter_info( pub fn print_fighter_info(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
title: &str, title: &str,
player_only: bool, player_only: bool,
cpu_only: bool, cpu_only: bool,

View file

@ -11,6 +11,7 @@ use PossessionState::*;
use crate::common::consts::{FighterId, HitstunPlayback, OnOff, RecordTrigger}; use crate::common::consts::{FighterId, HitstunPlayback, OnOff, RecordTrigger};
use crate::common::input::*; use crate::common::input::*;
use crate::common::offsets::OFFSET_SET_CPU_CONTROLS;
use crate::common::{button_config, is_training_mode}; use crate::common::{button_config, is_training_mode};
use crate::common::{ use crate::common::{
get_module_accessor, is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU, get_module_accessor, is_in_hitstun, is_in_shieldstun, try_get_module_accessor, MENU,
@ -434,7 +435,7 @@ pub unsafe fn handle_final_input_mapping(player_idx: i32, out: *mut MappedInputs
} }
} }
#[skyline::hook(offset = 0x2da180)] // After cpu controls are assigned from ai calls #[skyline::hook(offset = *OFFSET_SET_CPU_CONTROLS)] // After cpu controls are assigned from ai calls
unsafe fn set_cpu_controls(p_data: *mut *mut u8) { unsafe fn set_cpu_controls(p_data: *mut *mut u8) {
call_original!(p_data); call_original!(p_data);
if !is_training_mode() { if !is_training_mode() {

View file

@ -1,8 +1,9 @@
use crate::common::button_config; use crate::common::button_config;
use crate::common::consts::{BuffOption, FighterId, MENU};
use crate::common::offsets::*;
use crate::common::{ use crate::common::{
consts::BuffOption, consts::FighterId, consts::MENU, dev_config, get_module_accessor, dev_config, get_module_accessor, is_operation_cpu, is_training_mode, menu,
is_operation_cpu, is_training_mode, menu, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, FIGHTER_MANAGER_ADDR, ITEM_MANAGER_ADDR, STAGE_MANAGER_ADDR,
STAGE_MANAGER_ADDR,
}; };
use crate::hitbox_visualizer; use crate::hitbox_visualizer;
use crate::input::*; use crate::input::*;
@ -10,7 +11,9 @@ use crate::logging::*;
use crate::training::character_specific::{items, kirby, pikmin, ptrainer}; use crate::training::character_specific::{items, kirby, pikmin, ptrainer};
use skyline::hooks::{getRegionAddress, InlineCtx, Region}; use skyline::hooks::{getRegionAddress, InlineCtx, Region};
use skyline::nn::ro::LookupSymbol; use skyline::nn::ro::LookupSymbol;
use smash::app::{self, enSEType, lua_bind::*, utility}; use smash::app::{
enSEType, lua_bind::*, utility, BattleObjectModuleAccessor, FighterSpecializer_Jack,
};
use smash::lib::lua_const::*; use smash::lib::lua_const::*;
use smash::params::*; use smash::params::*;
use smash::phx::{Hash40, Vector3f}; use smash::phx::{Hash40, Vector3f};
@ -47,7 +50,7 @@ mod debug;
#[skyline::hook(replace = WorkModule::get_param_float)] #[skyline::hook(replace = WorkModule::get_param_float)]
pub unsafe fn handle_get_param_float( pub unsafe fn handle_get_param_float(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
param_type: u64, param_type: u64,
param_hash: u64, param_hash: u64,
) -> f32 { ) -> f32 {
@ -61,7 +64,7 @@ pub unsafe fn handle_get_param_float(
#[skyline::hook(replace = WorkModule::get_param_int)] #[skyline::hook(replace = WorkModule::get_param_int)]
pub unsafe fn handle_get_param_int( pub unsafe fn handle_get_param_int(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
param_type: u64, param_type: u64,
param_hash: u64, param_hash: u64,
) -> i32 { ) -> i32 {
@ -75,9 +78,7 @@ pub unsafe fn handle_get_param_int(
} }
#[skyline::hook(replace = ControlModule::get_attack_air_kind)] #[skyline::hook(replace = ControlModule::get_attack_air_kind)]
pub unsafe fn handle_get_attack_air_kind( pub unsafe fn handle_get_attack_air_kind(module_accessor: &mut BattleObjectModuleAccessor) -> i32 {
module_accessor: &mut app::BattleObjectModuleAccessor,
) -> i32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -91,7 +92,7 @@ pub unsafe fn handle_get_attack_air_kind(
#[skyline::hook(replace = ControlModule::get_command_flag_cat)] #[skyline::hook(replace = ControlModule::get_command_flag_cat)]
pub unsafe fn handle_get_command_flag_cat( pub unsafe fn handle_get_command_flag_cat(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
category: i32, category: i32,
) -> i32 { ) -> i32 {
let mut flag = original!()(module_accessor, category); let mut flag = original!()(module_accessor, category);
@ -116,10 +117,7 @@ pub unsafe fn handle_get_command_flag_cat(
flag flag
} }
fn once_per_frame_per_fighter( fn once_per_frame_per_fighter(module_accessor: &mut BattleObjectModuleAccessor, category: i32) {
module_accessor: &mut app::BattleObjectModuleAccessor,
category: i32,
) {
if category != FIGHTER_PAD_COMMAND_CATEGORY1 { if category != FIGHTER_PAD_COMMAND_CATEGORY1 {
return; return;
} }
@ -158,7 +156,7 @@ fn once_per_frame_per_fighter(
* 1 is fully right, -1 is fully left * 1 is fully right, -1 is fully left
*/ */
#[skyline::hook(replace = ControlModule::get_stick_x_no_clamp)] #[skyline::hook(replace = ControlModule::get_stick_x_no_clamp)]
pub unsafe fn get_stick_x_no_clamp(module_accessor: &mut app::BattleObjectModuleAccessor) -> f32 { pub unsafe fn get_stick_x_no_clamp(module_accessor: &mut BattleObjectModuleAccessor) -> f32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -173,7 +171,7 @@ pub unsafe fn get_stick_x_no_clamp(module_accessor: &mut app::BattleObjectModule
* 1 is fully up, -1 is fully down * 1 is fully up, -1 is fully down
*/ */
#[skyline::hook(replace = ControlModule::get_stick_y_no_clamp)] #[skyline::hook(replace = ControlModule::get_stick_y_no_clamp)]
pub unsafe fn get_stick_y_no_clamp(module_accessor: &mut app::BattleObjectModuleAccessor) -> f32 { pub unsafe fn get_stick_y_no_clamp(module_accessor: &mut BattleObjectModuleAccessor) -> f32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -188,7 +186,7 @@ pub unsafe fn get_stick_y_no_clamp(module_accessor: &mut app::BattleObjectModule
* Air Dodging * Air Dodging
*/ */
#[skyline::hook(replace = ControlModule::get_stick_x)] #[skyline::hook(replace = ControlModule::get_stick_x)]
pub unsafe fn get_stick_x(module_accessor: &mut app::BattleObjectModuleAccessor) -> f32 { pub unsafe fn get_stick_x(module_accessor: &mut BattleObjectModuleAccessor) -> f32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -202,7 +200,7 @@ pub unsafe fn get_stick_x(module_accessor: &mut app::BattleObjectModuleAccessor)
* angled ftilt/fsmash * angled ftilt/fsmash
*/ */
#[skyline::hook(replace = ControlModule::get_stick_dir)] #[skyline::hook(replace = ControlModule::get_stick_dir)]
pub unsafe fn get_stick_dir(module_accessor: &mut app::BattleObjectModuleAccessor) -> f32 { pub unsafe fn get_stick_dir(module_accessor: &mut BattleObjectModuleAccessor) -> f32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -226,7 +224,7 @@ pub unsafe fn get_stick_dir(module_accessor: &mut app::BattleObjectModuleAccesso
* Crouching * Crouching
*/ */
#[skyline::hook(replace = ControlModule::get_stick_y)] #[skyline::hook(replace = ControlModule::get_stick_y)]
pub unsafe fn get_stick_y(module_accessor: &mut app::BattleObjectModuleAccessor) -> f32 { pub unsafe fn get_stick_y(module_accessor: &mut BattleObjectModuleAccessor) -> f32 {
let ori = original!()(module_accessor); let ori = original!()(module_accessor);
if !is_training_mode() { if !is_training_mode() {
return ori; return ori;
@ -238,7 +236,7 @@ pub unsafe fn get_stick_y(module_accessor: &mut app::BattleObjectModuleAccessor)
#[skyline::hook(replace = ControlModule::check_button_on)] #[skyline::hook(replace = ControlModule::check_button_on)]
pub unsafe fn handle_check_button_on( pub unsafe fn handle_check_button_on(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
button: i32, button: i32,
) -> bool { ) -> bool {
let ori = original!()(module_accessor, button); let ori = original!()(module_accessor, button);
@ -252,7 +250,7 @@ pub unsafe fn handle_check_button_on(
#[skyline::hook(replace = ControlModule::check_button_off)] #[skyline::hook(replace = ControlModule::check_button_off)]
pub unsafe fn handle_check_button_off( pub unsafe fn handle_check_button_off(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
button: i32, button: i32,
) -> bool { ) -> bool {
let ori = original!()(module_accessor, button); let ori = original!()(module_accessor, button);
@ -266,7 +264,7 @@ pub unsafe fn handle_check_button_off(
#[skyline::hook(replace = MotionModule::change_motion)] #[skyline::hook(replace = MotionModule::change_motion)]
pub unsafe fn handle_change_motion( pub unsafe fn handle_change_motion(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
motion_kind: u64, motion_kind: u64,
unk1: f32, unk1: f32,
unk2: f32, unk2: f32,
@ -300,7 +298,7 @@ pub unsafe fn handle_change_motion(
#[skyline::hook(replace = WorkModule::is_enable_transition_term)] #[skyline::hook(replace = WorkModule::is_enable_transition_term)]
pub unsafe fn handle_is_enable_transition_term( pub unsafe fn handle_is_enable_transition_term(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
transition_term: i32, transition_term: i32,
) -> bool { ) -> bool {
let ori = original!()(module_accessor, transition_term); let ori = original!()(module_accessor, transition_term);
@ -332,7 +330,7 @@ pub unsafe fn handle_set_dead_rumble(lua_state: u64) -> u64 {
#[skyline::hook(replace = CameraModule::req_quake)] #[skyline::hook(replace = CameraModule::req_quake)]
pub unsafe fn handle_req_quake( pub unsafe fn handle_req_quake(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
my_int: i32, my_int: i32,
) -> u64 { ) -> u64 {
if !is_training_mode() { if !is_training_mode() {
@ -354,13 +352,11 @@ fn params_main(params_info: &ParamsInfo<'_>) {
} }
} }
static CLOUD_ADD_LIMIT_OFFSET: usize = 0x008dc140;
// this function is used to add limit to Cloud's limit gauge. Hooking it here so we can call it in buff.rs // this function is used to add limit to Cloud's limit gauge. Hooking it here so we can call it in buff.rs
#[skyline::hook(offset = CLOUD_ADD_LIMIT_OFFSET)] #[skyline::hook(offset = *OFFSET_CLOUD_ADD_LIMIT)]
pub unsafe fn handle_add_limit( pub unsafe fn handle_add_limit(
add_limit: f32, add_limit: f32,
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
is_special_lw: u64, is_special_lw: u64,
) { ) {
original!()(add_limit, module_accessor, is_special_lw) original!()(add_limit, module_accessor, is_special_lw)
@ -368,7 +364,7 @@ pub unsafe fn handle_add_limit(
#[skyline::hook(replace = EffectModule::req_screen)] // hooked to prevent the screen from darkening when loading a save state with One-Winged Angel #[skyline::hook(replace = EffectModule::req_screen)] // hooked to prevent the screen from darkening when loading a save state with One-Winged Angel
pub unsafe fn handle_req_screen( pub unsafe fn handle_req_screen(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
my_hash: Hash40, my_hash: Hash40,
bool_1: bool, bool_1: bool,
bool_2: bool, bool_2: bool,
@ -386,9 +382,9 @@ pub unsafe fn handle_req_screen(
original!()(module_accessor, my_hash, bool_1, bool_2, bool_3) original!()(module_accessor, my_hash, bool_1, bool_2, bool_3)
} }
#[skyline::hook(replace = app::FighterSpecializer_Jack::check_doyle_summon_dispatch)] // returns status of summon dispatch if triggered, -1 as u64 otherwise #[skyline::hook(replace = FighterSpecializer_Jack::check_doyle_summon_dispatch)] // returns status of summon dispatch if triggered, -1 as u64 otherwise
pub unsafe fn handle_check_doyle_summon_dispatch( pub unsafe fn handle_check_doyle_summon_dispatch(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
bool_1: bool, bool_1: bool,
bool_2: bool, bool_2: bool,
) -> u64 { ) -> u64 {
@ -402,7 +398,7 @@ pub unsafe fn handle_check_doyle_summon_dispatch(
ori ori
} }
#[skyline::hook(offset = 0x03ff9a0)] #[skyline::hook(offset = *OFFSET_ADD_DAMAGE)]
pub unsafe fn handle_add_damage( pub unsafe fn handle_add_damage(
damage_module: *mut u64, // DamageModule damage_module: *mut u64, // DamageModule
mut damage_to_add: f32, mut damage_to_add: f32,
@ -412,7 +408,7 @@ pub unsafe fn handle_add_damage(
return original!()(damage_module, damage_to_add, param_2); return original!()(damage_module, damage_to_add, param_2);
} }
let module_accessor = let module_accessor =
&mut **(damage_module.byte_add(0x8) as *mut *mut app::BattleObjectModuleAccessor); &mut **(damage_module.byte_add(0x8) as *mut *mut BattleObjectModuleAccessor);
// Prevent Wii Fit Deep Breathing from Healing on Save State Load // Prevent Wii Fit Deep Breathing from Healing on Save State Load
if utility::get_kind(module_accessor) == *FIGHTER_KIND_WIIFIT if utility::get_kind(module_accessor) == *FIGHTER_KIND_WIIFIT
&& buff::is_buffing(module_accessor) && buff::is_buffing(module_accessor)
@ -423,10 +419,8 @@ pub unsafe fn handle_add_damage(
} }
// Set Stale Moves to On // Set Stale Moves to On
static STALE_OFFSET: usize = 0x013e88a4;
// One instruction after stale moves toggle register is set to 0 // One instruction after stale moves toggle register is set to 0
#[skyline::hook(offset = STALE_OFFSET, inline)] #[skyline::hook(offset = *OFFSET_STALE, inline)]
unsafe fn stale_handle(ctx: &mut InlineCtx) { unsafe fn stale_handle(ctx: &mut InlineCtx) {
let x22 = ctx.registers[22].x.as_mut(); let x22 = ctx.registers[22].x.as_mut();
let training_structure_address = (*x22 + 0xb60) as *mut u8; let training_structure_address = (*x22 + 0xb60) as *mut u8;
@ -434,10 +428,8 @@ unsafe fn stale_handle(ctx: &mut InlineCtx) {
} }
// Set Stale Moves to On in the menu text // Set Stale Moves to On in the menu text
static STALE_MENU_OFFSET: usize = 0x013e88a0;
// One instruction after menu text register is set to off // One instruction after menu text register is set to off
#[skyline::hook(offset = STALE_MENU_OFFSET, inline)] #[skyline::hook(offset = *OFFSET_STALE_MENU, inline)]
unsafe fn stale_menu_handle(ctx: &mut InlineCtx) { unsafe fn stale_menu_handle(ctx: &mut InlineCtx) {
// Set the text pointer to where "mel_training_on" is located // Set the text pointer to where "mel_training_on" is located
let on_text_ptr = (getRegionAddress(Region::Text) as u64) + 0x42b215e; let on_text_ptr = (getRegionAddress(Region::Text) as u64) + 0x42b215e;
@ -447,7 +439,7 @@ unsafe fn stale_menu_handle(ctx: &mut InlineCtx) {
#[skyline::hook(replace = SoundModule::play_se)] // hooked to prevent death sfx from playing when loading save states #[skyline::hook(replace = SoundModule::play_se)] // hooked to prevent death sfx from playing when loading save states
pub unsafe fn handle_se( pub unsafe fn handle_se(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
my_hash: Hash40, my_hash: Hash40,
bool1: bool, bool1: bool,
bool2: bool, bool2: bool,
@ -493,12 +485,11 @@ pub unsafe fn handle_se(
#[repr(C)] #[repr(C)]
pub struct FighterSoundModule { pub struct FighterSoundModule {
vtable: u64, vtable: u64,
owner: *mut app::BattleObjectModuleAccessor, owner: *mut BattleObjectModuleAccessor,
} }
static PLAY_SE_OFFSET: usize = 0x04cf6a0;
// fighters don't use the symbol and go straight through their vtable to this function // fighters don't use the symbol and go straight through their vtable to this function
#[skyline::hook(offset = PLAY_SE_OFFSET)] #[skyline::hook(offset = *OFFSET_PLAY_SE)]
pub unsafe fn handle_fighter_play_se( pub unsafe fn handle_fighter_play_se(
sound_module: *mut FighterSoundModule, // pointer to fighter's SoundModule sound_module: *mut FighterSoundModule, // pointer to fighter's SoundModule
mut my_hash: Hash40, mut my_hash: Hash40,
@ -534,15 +525,10 @@ pub unsafe fn handle_fighter_play_se(
original!()(sound_module, my_hash, bool1, bool2, bool3, bool4, se_type) original!()(sound_module, my_hash, bool1, bool2, bool3, bool4, se_type)
} }
pub struct FighterEffectModule { // hooked to prevent score gfx from playing when loading save states
_vtable: u64, #[skyline::hook(replace = EffectModule::req_follow)]
owner: *mut app::BattleObjectModuleAccessor,
}
static FOLLOW_REQ_OFFSET: usize = 0x044f860;
#[skyline::hook(offset = FOLLOW_REQ_OFFSET)] // hooked to prevent score gfx from playing when loading save states
pub unsafe fn handle_effect_follow( pub unsafe fn handle_effect_follow(
effect_module: &mut FighterEffectModule, module_accessor: &mut BattleObjectModuleAccessor,
eff_hash: Hash40, eff_hash: Hash40,
joint_hash: Hash40, joint_hash: Hash40,
pos: *const Vector3f, pos: *const Vector3f,
@ -559,7 +545,7 @@ pub unsafe fn handle_effect_follow(
) -> u64 { ) -> u64 {
if !is_training_mode() { if !is_training_mode() {
return original!()( return original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
joint_hash, joint_hash,
pos, pos,
@ -580,7 +566,7 @@ pub unsafe fn handle_effect_follow(
size = 0.0 size = 0.0
} }
original!()( original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
joint_hash, joint_hash,
pos, pos,
@ -597,10 +583,9 @@ pub unsafe fn handle_effect_follow(
) )
} }
static EFFECT_REQ_OFFSET: usize = 0x44de50; #[skyline::hook(replace = EffectModule::req)] // hooked to prevent death gfx from playing when loading save states
#[skyline::hook(offset = EFFECT_REQ_OFFSET)] // hooked to prevent death gfx from playing when loading save states
pub unsafe fn handle_fighter_effect( pub unsafe fn handle_fighter_effect(
effect_module: *mut FighterEffectModule, // pointer to effect module module_accessor: &mut BattleObjectModuleAccessor,
eff_hash: Hash40, eff_hash: Hash40,
pos: *const Vector3f, pos: *const Vector3f,
rot: *const Vector3f, rot: *const Vector3f,
@ -612,7 +597,7 @@ pub unsafe fn handle_fighter_effect(
) -> u64 { ) -> u64 {
if !is_training_mode() { if !is_training_mode() {
return original!()( return original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
pos, pos,
rot, rot,
@ -623,9 +608,9 @@ pub unsafe fn handle_fighter_effect(
arg9, arg9,
); );
} }
size = ptrainer::handle_pokemon_effect(&mut *(*effect_module).owner, eff_hash, size); size = ptrainer::handle_pokemon_effect(module_accessor, eff_hash, size);
original!()( original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
pos, pos,
rot, rot,
@ -637,10 +622,9 @@ pub unsafe fn handle_fighter_effect(
) )
} }
static JOINT_EFFECT_REQ_OFFSET: usize = 0x44e1e0; #[skyline::hook(replace = EffectModule::req_on_joint)] // hooked to prevent death gfx from playing when loading save states
#[skyline::hook(offset = JOINT_EFFECT_REQ_OFFSET)] // hooked to prevent death gfx from playing when loading save states
pub unsafe fn handle_fighter_joint_effect( pub unsafe fn handle_fighter_joint_effect(
effect_module: *mut FighterEffectModule, // pointer to effect module module_accessor: &mut BattleObjectModuleAccessor,
eff_hash: Hash40, eff_hash: Hash40,
joint_hash: Hash40, joint_hash: Hash40,
pos: *const Vector3f, pos: *const Vector3f,
@ -655,7 +639,7 @@ pub unsafe fn handle_fighter_joint_effect(
) -> u64 { ) -> u64 {
if !is_training_mode() { if !is_training_mode() {
return original!()( return original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
joint_hash, joint_hash,
pos, pos,
@ -669,9 +653,9 @@ pub unsafe fn handle_fighter_joint_effect(
arg9, arg9,
); );
} }
size = ptrainer::handle_pokemon_effect(&mut *(*effect_module).owner, eff_hash, size); size = ptrainer::handle_pokemon_effect(module_accessor, eff_hash, size);
original!()( original!()(
effect_module, module_accessor,
eff_hash, eff_hash,
joint_hash, joint_hash,
pos, pos,
@ -688,7 +672,7 @@ pub unsafe fn handle_fighter_joint_effect(
#[skyline::hook(replace = EffectModule::req)] // hooked to prevent death gfx from playing when loading save states #[skyline::hook(replace = EffectModule::req)] // hooked to prevent death gfx from playing when loading save states
pub unsafe fn handle_effect( pub unsafe fn handle_effect(
module_accessor: &mut app::BattleObjectModuleAccessor, module_accessor: &mut BattleObjectModuleAccessor,
eff_hash: Hash40, eff_hash: Hash40,
pos: *const Vector3f, pos: *const Vector3f,
rot: *const Vector3f, rot: *const Vector3f,
@ -738,10 +722,8 @@ pub unsafe fn handle_effect(
) )
} }
static CAN_FUTTOBI_BACK_OFFSET: usize = 0x0260f950;
// can_futtobi_back, checks if stage allows for star KOs // can_futtobi_back, checks if stage allows for star KOs
#[skyline::hook(offset = CAN_FUTTOBI_BACK_OFFSET)] #[skyline::hook(offset = *OFFSET_CAN_FUTTOBI_BACK)]
pub unsafe fn handle_star_ko(my_long_ptr: &mut u64) -> bool { pub unsafe fn handle_star_ko(my_long_ptr: &mut u64) -> bool {
let ori = original!()(my_long_ptr); let ori = original!()(my_long_ptr);
if !is_training_mode() { if !is_training_mode() {
@ -751,9 +733,8 @@ pub unsafe fn handle_star_ko(my_long_ptr: &mut u64) -> bool {
} }
} }
static REUSED_UI_OFFSET: usize = 0x068cd80;
// A function reused by many functions to update UI. Called to update at least Little Mac's meter. // A function reused by many functions to update UI. Called to update at least Little Mac's meter.
#[skyline::hook(offset = REUSED_UI_OFFSET)] #[skyline::hook(offset = *OFFSET_REUSED_UI)]
pub unsafe fn handle_reused_ui( pub unsafe fn handle_reused_ui(
fighter_data: *mut u32, // a pointer to length 4 data in the Fighter's FighterEntry in the FighterManager fighter_data: *mut u32, // a pointer to length 4 data in the Fighter's FighterEntry in the FighterManager
mut param_2: u32, // In Little Mac's case, the meter value as an integer mut param_2: u32, // In Little Mac's case, the meter value as an integer
@ -779,22 +760,18 @@ pub unsafe fn handle_reused_ui(
original!()(fighter_data, param_2) original!()(fighter_data, param_2)
} }
static ARTICLE_GET_INT_OFFSET: usize = 0x3d5920; #[skyline::hook(replace = ArticleModule::get_int)]
#[skyline::hook(offset = ARTICLE_GET_INT_OFFSET)]
pub unsafe fn handle_article_get_int( pub unsafe fn handle_article_get_int(
article_module: *mut app::BattleObjectModuleAccessor, // *mut ArticleModule module_accessor: *mut BattleObjectModuleAccessor,
generate_article: i32, generate_article: i32,
address: i32, address: i32,
) -> i32 { ) -> i32 {
original!()(article_module, generate_article, address) original!()(module_accessor, generate_article, address)
} }
// Instruction run on the completion of the CPU Control function // Instruction run on the completion of the CPU Control function
static OPCF_OFFSET: usize = 0x06b7fdc;
// One instruction after the CPU Control function completes // One instruction after the CPU Control function completes
#[skyline::hook(offset = OPCF_OFFSET, inline)] #[skyline::hook(offset = *OFFSET_OPCF, inline)]
unsafe fn handle_once_per_cpu_frame(_ctx: &mut InlineCtx) { unsafe fn handle_once_per_cpu_frame(_ctx: &mut InlineCtx) {
input_record::handle_recording(); input_record::handle_recording();
frame_counter::tick_ingame(); frame_counter::tick_ingame();
@ -808,9 +785,7 @@ unsafe fn handle_once_per_cpu_frame(_ctx: &mut InlineCtx) {
} }
} }
static FIM_OFFSET: usize = 0x17504a0; #[skyline::hook(offset = *OFFSET_FIM)]
// 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( unsafe fn handle_final_input_mapping(
mappings: *mut ControllerMapping, 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? 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?
@ -881,8 +856,7 @@ pub fn training_mods() {
// Enable Custom Stages for Training Mode // Enable Custom Stages for Training Mode
// Specifically, we prevent a field in StageSelectInfo of the Scene that controls if the Custom Stage tab is loaded // Specifically, we prevent a field in StageSelectInfo of the Scene that controls if the Custom Stage tab is loaded
// from being set to false when we load the SSS in Training Mode // from being set to false when we load the SSS in Training Mode
static SSS_TRAINING_OFFSET: usize = 0x184d1d8; skyline::patching::Patch::in_text(*OFFSET_SSS_TRAINING)
skyline::patching::Patch::in_text(SSS_TRAINING_OFFSET)
.nop() .nop()
.unwrap(); .unwrap();
@ -922,8 +896,8 @@ pub fn training_mods() {
// Buff SFX // Buff SFX
handle_fighter_play_se, handle_fighter_play_se,
// Stale Moves // Stale Moves
stale_menu_handle, // This has to be initialized before stale_handle otherwise the offset search fails
stale_handle, stale_handle,
stale_menu_handle,
// Death SFX // Death SFX
handle_se, handle_se,
// Death GFX // Death GFX

View file

@ -6,6 +6,9 @@ use smash::lua2cpp::L2CFighterBase;
use smash::phx::{Hash40, Vector3f}; use smash::phx::{Hash40, Vector3f};
use crate::common::consts::*; use crate::common::consts::*;
use crate::common::offsets::OFFSET_CHANGE_ACTIVE_CAMERA;
use crate::common::offsets::OFFSET_SET_TRAINING_FIXED_CAMERA_VALUES;
use crate::common::*; use crate::common::*;
use crate::training::{frame_counter, mash, save_states}; use crate::training::{frame_counter, mash, save_states};
@ -393,31 +396,25 @@ pub unsafe fn hide_tech() {
} }
} }
pub struct FighterCameraModule {
_vtable: u64,
owner: *mut BattleObjectModuleAccessor,
}
// Prevent Mistech Quake // Prevent Mistech Quake
#[skyline::hook(offset = 0x3ec820)] #[skyline::hook(replace = CameraModule::req_quake_pos)]
pub unsafe fn handle_fighter_req_quake_pos( pub unsafe fn handle_fighter_req_quake_pos(
camera_module: &mut FighterCameraModule, module_accessor: &mut BattleObjectModuleAccessor,
quake_kind: i32, quake_kind: i32,
) -> u64 { ) -> u64 {
let module_accessor = camera_module.owner;
if !is_training_mode() || !is_operation_cpu(&mut *module_accessor) { if !is_training_mode() || !is_operation_cpu(&mut *module_accessor) {
return original!()(camera_module, quake_kind); return original!()(module_accessor, quake_kind);
} }
let status = StatusModule::status_kind(module_accessor); let status = StatusModule::status_kind(module_accessor);
if status == FIGHTER_STATUS_KIND_DOWN && MENU.tech_hide == OnOff::ON { if status == FIGHTER_STATUS_KIND_DOWN && MENU.tech_hide == OnOff::ON {
// We're hiding techs, prevent mistech quake from giving away missed tech // We're hiding techs, prevent mistech quake from giving away missed tech
return original!()(camera_module, *CAMERA_QUAKE_KIND_NONE); return original!()(module_accessor, *CAMERA_QUAKE_KIND_NONE);
} }
original!()(camera_module, quake_kind) original!()(module_accessor, quake_kind)
} }
// Zoom in the Fixed Camera view while this is on to set up a good situation for practice // Zoom in the Fixed Camera view while this is on to set up a good situation for practice
#[skyline::hook(offset = 0x4ee460)] #[skyline::hook(offset = *OFFSET_CHANGE_ACTIVE_CAMERA)]
pub unsafe fn handle_change_active_camera( pub unsafe fn handle_change_active_camera(
camera_manager: *mut u64, camera_manager: *mut u64,
camera_mode: i32, camera_mode: i32,
@ -733,7 +730,7 @@ fn get_stage_camera_values(stage_id: i32) -> Option<Vector3f> {
} }
// We hook where the training fixed camera fields are initially set, so we can change them later if necessary // We hook where the training fixed camera fields are initially set, so we can change them later if necessary
#[skyline::hook(offset = 0x3157bb0)] #[skyline::hook(offset = *OFFSET_SET_TRAINING_FIXED_CAMERA_VALUES)]
pub unsafe fn handle_set_training_fixed_camera_values( pub unsafe fn handle_set_training_fixed_camera_values(
camera_manager: *mut u64, // not actually camera manager - is this even used????? camera_manager: *mut u64, // not actually camera manager - is this even used?????
fixed_camera_values: &mut CameraValuesForTraining, fixed_camera_values: &mut CameraValuesForTraining,

View file

@ -5,12 +5,12 @@ use skyline::nn::ui2d::*;
use smash::ui2d::SmashTextBox; use smash::ui2d::SmashTextBox;
use training_mod_consts::{OnOff, MENU}; use training_mod_consts::{OnOff, MENU};
use crate::common::menu::QUICK_MENU_ACTIVE;
use crate::common::offsets::{OFFSET_DRAW, OFFSET_LAYOUT_ARC_MALLOC};
use crate::common::{is_ready_go, is_training_mode};
#[cfg(feature = "layout_arc_from_file")] #[cfg(feature = "layout_arc_from_file")]
use crate::consts::LAYOUT_ARC_PATH; use crate::consts::LAYOUT_ARC_PATH;
use crate::{ use crate::training::frame_counter;
common::{is_ready_go, is_training_mode, menu::QUICK_MENU_ACTIVE},
training::frame_counter,
};
mod damage; mod damage;
mod display; mod display;
@ -52,7 +52,7 @@ pub fn fade_out(pane: &mut Pane, current_frame: u32, total_frames: u32) {
} }
} }
#[skyline::hook(offset = 0x4b620)] #[skyline::hook(offset = *OFFSET_DRAW)]
pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) { pub unsafe fn handle_draw(layout: *mut Layout, draw_info: u64, cmd_buffer: u64) {
let layout_name = skyline::from_c_str((*layout).layout_name); let layout_name = skyline::from_c_str((*layout).layout_name);
let root_pane = &mut *(*layout).root_pane; let root_pane = &mut *(*layout).root_pane;
@ -128,7 +128,7 @@ static mut LAYOUT_ARC: &mut [u8; LAYOUT_ARC_SIZE] = &mut [0u8; LAYOUT_ARC_SIZE];
/// label_material.set_white_res_color(LABEL_WHITE_SELECTED_COLOR); /// label_material.set_white_res_color(LABEL_WHITE_SELECTED_COLOR);
/// label_material.set_black_res_color(LABEL_BLACK_SELECTED_COLOR); /// label_material.set_black_res_color(LABEL_BLACK_SELECTED_COLOR);
/// ``` /// ```
#[skyline::hook(offset = 0x37730d4, inline)] #[skyline::hook(offset = *OFFSET_LAYOUT_ARC_MALLOC, inline)]
unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) { unsafe fn handle_layout_arc_malloc(ctx: &mut skyline::hooks::InlineCtx) {
if !is_training_mode() { if !is_training_mode() {
return; return;