mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 10:54:16 +00:00
initial rust migration
This commit is contained in:
parent
587da8f9ef
commit
8ab1d8a0d8
5 changed files with 516 additions and 22 deletions
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "skyline_rs_template"
|
||||
name = "training_modpack"
|
||||
version = "0.1.0"
|
||||
authors = ["jam1garner <jam1.mcleod@hotmail.com>"]
|
||||
edition = "2018"
|
||||
|
@ -17,3 +17,6 @@ panic = "abort"
|
|||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = true
|
||||
|
||||
[package.metadata.skyline]
|
||||
titleid = "01006A800016E000"
|
||||
|
|
93
src/common/consts.rs
Normal file
93
src/common/consts.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
pub const NONE : i32 = 0;
|
||||
|
||||
// Side Taunt
|
||||
|
||||
// DI
|
||||
/*
|
||||
0, 0.785398, 1.570796, 2.356194, -3.14159, -2.356194, -1.570796, -0.785398
|
||||
0, pi/4, pi/2, 3pi/4, pi, 5pi/4, 3pi/2, 7pi/4
|
||||
*/
|
||||
|
||||
/* DI */
|
||||
pub static mut DI_STATE : i32 = NONE;
|
||||
pub const DI_RANDOM_IN_AWAY : i32 = 9;
|
||||
// const std::vector<std::string> di_items{"None", "Out", "Up Out", "Up", "Up In", "In", "Down In", "Down", "Down Out", "Random"};
|
||||
|
||||
// Attack Option
|
||||
pub const MASH_NAIR : i32 = 0;
|
||||
pub const MASH_FAIR : i32 = 1;
|
||||
pub const MASH_BAIR : i32 = 2;
|
||||
pub const MASH_UPAIR : i32 = 3;
|
||||
pub const MASH_DAIR : i32 = 4;
|
||||
pub const MASH_NEUTRAL_B : i32 = 5;
|
||||
pub const MASH_SIDE_B : i32 = 6;
|
||||
pub const MASH_UP_B : i32 = 7;
|
||||
pub const MASH_DOWN_B : i32 = 8;
|
||||
pub const MASH_UP_SMASH : i32 = 9;
|
||||
pub const MASH_GRAB : i32 = 10;
|
||||
// pub const std::vector<std::string> attack_items{"Neutral Air", "Forward Air", "Back Air", "Up Air", "Down Air", "Neutral B", "Side B", "Up B", "Down B", "Up Smash", "Grab"};
|
||||
|
||||
// Ledge Option
|
||||
pub const RANDOM_LEDGE : i32 = 1;
|
||||
pub const NEUTRAL_LEDGE : i32 = 2;
|
||||
pub const ROLL_LEDGE : i32 = 3;
|
||||
pub const JUMP_LEDGE : i32 = 4;
|
||||
pub const ATTACK_LEDGE : i32 = 5;
|
||||
// pub const std::vector<std::string> ledge_items{"None", "Random", "Ntrl. Getup", "Roll", "Jump", "Attack"};
|
||||
|
||||
// Tech Option
|
||||
pub const RANDOM_TECH : i32 = 1;
|
||||
pub const TECH_IN_PLACE : i32 = 2;
|
||||
pub const TECH_ROLL : i32 = 3;
|
||||
pub const TECH_MISS : i32 = 4;
|
||||
// pub const std::vector<std::string> tech_items{"None", "Random", "In-Place", "Roll", "Miss Tech"};
|
||||
|
||||
// Mash States
|
||||
pub const MASH_AIRDODGE : i32 = 1;
|
||||
pub const MASH_JUMP : i32 = 2;
|
||||
pub const MASH_ATTACK : i32 = 3;
|
||||
pub const MASH_SPOTDODGE : i32 = 4;
|
||||
pub const MASH_RANDOM : i32 = 5;
|
||||
// pub const std::vector<std::string> mash_items{"None", "Airdodge", "Jump", "Attack", "Spotdodge", "Random"};
|
||||
|
||||
// Shield States
|
||||
pub const SHIELD_INFINITE : i32 = 1;
|
||||
pub const SHIELD_HOLD : i32 = 2;
|
||||
// pub const std::vector<std::string> shield_items{"None", "Infinite", "Hold"};
|
||||
|
||||
// Defensive States
|
||||
pub const RANDOM_DEFENSIVE : i32 = 1;
|
||||
pub const DEFENSIVE_SPOTDODGE : i32 = 2;
|
||||
pub const DEFENSIVE_ROLL : i32 = 3;
|
||||
pub const DEFENSIVE_JAB : i32 = 4;
|
||||
pub const DEFENSIVE_SHIELD : i32 = 5;
|
||||
// pub const std::vector<std::string> defensive_items{"None", "Random", "Spotdodge", "Roll", "Jab", "Flash Shield"};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TrainingModpackMenu
|
||||
{
|
||||
pub HITBOX_VIS : bool,
|
||||
pub DI_STATE : i32,
|
||||
pub ATTACK_STATE : i32,
|
||||
pub LEDGE_STATE : i32,
|
||||
pub TECH_STATE : i32,
|
||||
pub MASH_STATE : i32,
|
||||
pub SHIELD_STATE : i32,
|
||||
pub DEFENSIVE_STATE : i32,
|
||||
}
|
||||
|
||||
impl Default for TrainingModpackMenu {
|
||||
fn default() -> TrainingModpackMenu {
|
||||
TrainingModpackMenu {
|
||||
HITBOX_VIS : true,
|
||||
DI_STATE : NONE,
|
||||
ATTACK_STATE : MASH_NAIR,
|
||||
LEDGE_STATE : RANDOM_LEDGE,
|
||||
TECH_STATE : RANDOM_TECH,
|
||||
MASH_STATE : NONE,
|
||||
SHIELD_STATE : NONE,
|
||||
DEFENSIVE_STATE : RANDOM_DEFENSIVE,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
90
src/common/mod.rs
Normal file
90
src/common/mod.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
pub mod consts;
|
||||
|
||||
use smash::lib::lua_const::{*};
|
||||
use crate::common::consts::*;
|
||||
use smash::app::{self};
|
||||
use smash::app::lua_bind::*;
|
||||
use smash::hash40;
|
||||
|
||||
pub static menu : consts::TrainingModpackMenu = consts::TrainingModpackMenu{
|
||||
HITBOX_VIS : true,
|
||||
DI_STATE : NONE,
|
||||
ATTACK_STATE : MASH_NAIR,
|
||||
LEDGE_STATE : RANDOM_LEDGE,
|
||||
TECH_STATE : RANDOM_TECH,
|
||||
MASH_STATE : NONE,
|
||||
SHIELD_STATE : NONE,
|
||||
DEFENSIVE_STATE : RANDOM_DEFENSIVE,
|
||||
};
|
||||
|
||||
static fighter_manager_addr: u64 = 0;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "\u{1}_ZN3app9smashball16is_training_modeEv"]
|
||||
pub fn is_training_mode() -> bool;
|
||||
}
|
||||
|
||||
// pub fn get_category(module_accessor: &mut app::BattleObjectModuleAccessor) -> u8 {
|
||||
// return (u8)(*(u32*)(module_accessor + 8) >> 28);
|
||||
// }
|
||||
|
||||
// pub fn is_operation_cpu(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool{
|
||||
// if (get_category(module_accessor) != BATTLE_OBJECT_CATEGORY_FIGHTER)
|
||||
// return false;
|
||||
|
||||
// let entry_id = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID) as i32;
|
||||
// u64 fighter_information = FighterManager::get_fighter_information(LOAD64(fighter_manager_addr), entry_id);
|
||||
|
||||
// return FighterInformation::is_operation_cpu(fighter_information);
|
||||
// }
|
||||
|
||||
pub unsafe fn is_in_hitstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
||||
return status_kind >= FIGHTER_STATUS_KIND_DAMAGE &&
|
||||
status_kind <= FIGHTER_STATUS_KIND_DAMAGE_FALL;
|
||||
}
|
||||
|
||||
pub unsafe fn is_in_shieldstun(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
||||
let prev_status = StatusModule::prev_status_kind(module_accessor, 0) as i32;
|
||||
// If we are taking shield damage or we are droping shield from taking shield damage we are in hitstun
|
||||
if status_kind == FIGHTER_STATUS_KIND_GUARD_DAMAGE ||
|
||||
(prev_status == FIGHTER_STATUS_KIND_GUARD_DAMAGE && status_kind == FIGHTER_STATUS_KIND_GUARD_OFF) {
|
||||
return true
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
pub unsafe fn is_in_landing(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
||||
(FIGHTER_STATUS_KIND_LANDING..FIGHTER_STATUS_KIND_LANDING_DAMAGE_LIGHT)
|
||||
.contains(&status_kind)
|
||||
}
|
||||
|
||||
|
||||
// pub fn perform_defensive_option(module_accessor: &mut app::BattleObjectModuleAccessor, flag: &i32) {
|
||||
// if menu.DEFENSIVE_STATE == RANDOM_DEFENSIVE {
|
||||
// let NUM_DEFENSIVE_CMDS = 4;
|
||||
// let random_cmds = vec![
|
||||
// FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE,
|
||||
// FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F,
|
||||
// FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B,
|
||||
// FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N
|
||||
// ];
|
||||
|
||||
// let random_cmd_index = app::sv_math::rand(hash40("fighter"), random_cmds.len() as i32) as usize;
|
||||
// flag |= random_cmds[random_cmd_index];
|
||||
// } else if menu.DEFENSIVE_STATE == DEFENSIVE_ROLL {
|
||||
// if app::sv_math::rand(hash40("fighter"), 2) == 0 {
|
||||
// flag |= FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_F;
|
||||
// } else {
|
||||
// flag |= FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE_B;
|
||||
// }
|
||||
// } else if menu.DEFENSIVE_STATE == DEFENSIVE_SPOTDODGE {
|
||||
// flag |= FIGHTER_PAD_CMD_CAT1_FLAG_ESCAPE;
|
||||
// } else if menu.DEFENSIVE_STATE == DEFENSIVE_JAB {
|
||||
// flag |= FIGHTER_PAD_CMD_CAT1_FLAG_ATTACK_N;
|
||||
// }
|
||||
// }
|
272
src/hitbox_visualizer/mod.rs
Normal file
272
src/hitbox_visualizer/mod.rs
Normal file
|
@ -0,0 +1,272 @@
|
|||
use smash::hash40;
|
||||
use smash::app::BattleObjectModuleAccessor;
|
||||
use smash::app::sv_animcmd::{self};
|
||||
use smash::app::lua_bind::*;
|
||||
use smash::lib::{self, L2CAgent, L2CValue};
|
||||
use smash::phx::{Hash40, Vector3f};
|
||||
use smash::lib::lua_const::{*};
|
||||
use smash::app::sv_system::{self};
|
||||
use smash::app::{self};
|
||||
use skyline::logging::hex_dump_ptr;
|
||||
use crate::common::*;
|
||||
|
||||
/**
|
||||
* Rounds a number to the nearest multiple of another number.
|
||||
*/
|
||||
pub fn round_to(val: f32, align: f32) -> f32 { (val / align).round() * align }
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two numbers, without bounds checking.
|
||||
*/
|
||||
pub fn lerp(min: f32, max: f32, t: f32) -> f32 { min + (max - min) * t }
|
||||
|
||||
pub fn unlerp(min: f32, max: f32, val: f32) -> f32 { (val - min) / (max - min) }
|
||||
|
||||
/**
|
||||
* Linearly interpolates between two numbers, with bounds checking.
|
||||
*/
|
||||
pub fn lerp_bounded(min: f32, max: f32, t: f32) -> f32 {
|
||||
if t <= 0.0 { min } else { if t >= 1.0 { max } else { lerp(min, max, t) } }
|
||||
}
|
||||
|
||||
pub fn unlerp_bounded(min: f32, max: f32, val: f32) -> f32 {
|
||||
if val <= min { 0.0 } else { if val >= max { 1.0 } else { unlerp(min, max, val)} }
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly nterpolates between two colors, with bounds checking, accounting for
|
||||
* gamma. arguments:
|
||||
* - min_color (Vector3f) -- xyz maps to rgb, components are usually in the
|
||||
* range [0.0f, 1.0f] but can go beyond to account for super-bright or
|
||||
* super-dark colors
|
||||
* - max_Color (Vector3f) -- same as minColor
|
||||
* - t (float) -- how far to interpolate between the colors
|
||||
* - gamma (float = 2.0f) -- used for color correction, helps avoid ugly dark
|
||||
* colors when interpolating b/t bright colors
|
||||
*/
|
||||
|
||||
pub fn color_lerp(min_color: Vector3f, max_color: Vector3f, t: f32,
|
||||
gamma: f32) -> Vector3f {
|
||||
let gamma_inv = 1.0 / gamma;
|
||||
let align =
|
||||
1.0 / 255.0; // color components must be a multiple of 1/255
|
||||
Vector3f{x: round_to(lerp_bounded(min_color.x.powf(gamma),
|
||||
max_color.x.powf(gamma), t).powf(
|
||||
gamma_inv),
|
||||
align),
|
||||
y: round_to(lerp_bounded(min_color.y.powf(gamma),
|
||||
max_color.y.powf(gamma), t).powf(
|
||||
gamma_inv),
|
||||
align),
|
||||
z: round_to(lerp_bounded(min_color.z.powf(gamma),
|
||||
max_color.z.powf(gamma), t).powf(
|
||||
gamma_inv),
|
||||
align)}
|
||||
}
|
||||
|
||||
const ID_COLORS: &[Vector3f] = &[
|
||||
// used to tint the hitbox effects -- make sure that at least one component
|
||||
// is equal to 1.0
|
||||
Vector3f{x: 1.0, y: 0.0, z: 0.0}, // #ff0000 (red)
|
||||
Vector3f{x: 1.0, y: 0.4, z: 0.0}, // #ff9900 (orange)
|
||||
Vector3f{x: 0.8, y: 1.0, z: 0.0}, // #ccff00 (yellow)
|
||||
Vector3f{x: 0.2, y: 1.0, z: 0.2}, // #00ff33 (green)
|
||||
Vector3f{x: 0.0, y: 0.8, z: 1.0}, // #00ccff (sky blue)
|
||||
Vector3f{x: 0.4, y: 0.4, z: 1.0}, // #6666ff (blue)
|
||||
Vector3f{x: 0.8, y: 0.0, z: 1.0}, // #cc00ff (purple)
|
||||
Vector3f{x: 1.0, y: 0.2, z: 0.8}, // #ff33cc (pink)
|
||||
];
|
||||
const MAX_EFFECTS_PER_HITBOX: i32 = 16; // max # of circles drawn for an extended hitbox
|
||||
|
||||
pub unsafe fn wrap(func: unsafe extern "C" fn(lua_state: u64), agent: &mut L2CAgent, vals: &mut Vec::<L2CValue>) {
|
||||
agent.clear_lua_stack();
|
||||
for val in vals {
|
||||
agent.push_lua_stack(val);
|
||||
}
|
||||
func(agent.lua_state_agent);
|
||||
agent.clear_lua_stack();
|
||||
}
|
||||
|
||||
pub unsafe fn generate_hitbox_effects(l2c_agent: &mut L2CAgent, bone: L2CValue,
|
||||
size: L2CValue, x: L2CValue, y: L2CValue,
|
||||
z: L2CValue, x2: L2CValue, y2: L2CValue,
|
||||
z2: L2CValue, color: Vector3f) {
|
||||
let red = L2CValue::new_num(color.x);
|
||||
let green = L2CValue::new_num(color.y);
|
||||
let blue = L2CValue::new_num(color.z);
|
||||
|
||||
let size_mult = 19.0 / 200.0;
|
||||
|
||||
let shield_effect = L2CValue::new_int(hash40("sys_shield"));
|
||||
let zero_rot = L2CValue::new_num(0.0);
|
||||
let terminate = L2CValue::new_bool(true);
|
||||
let effect_size = L2CValue::new_num(size.get_num() * size_mult);
|
||||
|
||||
let rate = L2CValue::new_num(8.0);
|
||||
|
||||
let x_dist : f32;
|
||||
let y_dist : f32;
|
||||
let z_dist : f32;
|
||||
let mut n_effects : i32;
|
||||
if let lib::L2CValueType::Void = x2.val_type{ // && let lib::L2CValueType::Void = y2.val_type && let lib::L2CValueType::Void = z2.val_type { // extended hitbox
|
||||
x_dist = 0.0; y_dist = 0.0; z_dist = 0.0;
|
||||
n_effects = 1;
|
||||
}
|
||||
else { // non-extended hitbox
|
||||
x_dist = x2.get_num() - x.get_num();
|
||||
y_dist = y2.get_num() - y.get_num();
|
||||
z_dist = z2.get_num() - z.get_num();
|
||||
let dist_sq : f32 = x_dist * x_dist + y_dist * y_dist + z_dist * z_dist;
|
||||
let dist = dist_sq.sqrt();
|
||||
n_effects = ((dist / (size.get_num() * 1.75)) + 1.0).ceil() as i32; // just enough effects to form a continuous line
|
||||
if n_effects < 2 {
|
||||
n_effects = 2;
|
||||
} else if n_effects > MAX_EFFECTS_PER_HITBOX {
|
||||
n_effects = MAX_EFFECTS_PER_HITBOX;
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..n_effects {
|
||||
let mut t = 0.0;
|
||||
if n_effects > 1 {
|
||||
t = (i as f32) / ((n_effects - 1) as f32);
|
||||
}
|
||||
let x_curr = L2CValue::new_num(x.get_num() + x_dist * t);
|
||||
let y_curr = L2CValue::new_num(y.get_num() + y_dist * t);
|
||||
let z_curr = L2CValue::new_num(z.get_num() + z_dist * t);
|
||||
|
||||
wrap(sv_animcmd::EFFECT_FOLLOW_NO_SCALE,
|
||||
l2c_agent,
|
||||
&mut [
|
||||
shield_effect, bone, x_curr,
|
||||
y_curr, z_curr, zero_rot, zero_rot,
|
||||
zero_rot, effect_size, terminate].to_vec());
|
||||
|
||||
// set to hitbox ID color
|
||||
wrap(sv_animcmd::LAST_EFFECT_SET_COLOR, l2c_agent,
|
||||
&mut [red, green, blue].to_vec());
|
||||
|
||||
// speed up animation by rate to remove pulsing effect
|
||||
wrap(sv_animcmd::LAST_EFFECT_SET_RATE, l2c_agent,
|
||||
&mut [rate].to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
#[skyline::hook(replace = sv_animcmd::ATTACK)]
|
||||
unsafe fn handle_attack(lua_state: u64) {
|
||||
let mut l2c_agent = L2CAgent::new(lua_state);
|
||||
|
||||
// get all necessary hitbox params
|
||||
let id = l2c_agent.pop_lua_stack(1); // int
|
||||
let bone = l2c_agent.pop_lua_stack(3); // hash40
|
||||
let damage = l2c_agent.pop_lua_stack(4); // float
|
||||
let _angle = l2c_agent.pop_lua_stack(5); // int
|
||||
let kbg = l2c_agent.pop_lua_stack(6); // int
|
||||
let fkb = l2c_agent.pop_lua_stack(7); // int
|
||||
let bkb = l2c_agent.pop_lua_stack(8); // int
|
||||
let size = l2c_agent.pop_lua_stack(9); // float
|
||||
let x = l2c_agent.pop_lua_stack(10); // float
|
||||
let y = l2c_agent.pop_lua_stack(11); // float
|
||||
let z = l2c_agent.pop_lua_stack(12); // float
|
||||
let x2 = l2c_agent.pop_lua_stack(13); // float or void
|
||||
let y2 = l2c_agent.pop_lua_stack(14); // float or void
|
||||
let z2 = l2c_agent.pop_lua_stack(15); // float or void
|
||||
|
||||
original!()(lua_state);
|
||||
|
||||
if menu.HITBOX_VIS && is_training_mode() { // generate hitbox effect(s)
|
||||
let color_scale: f32;
|
||||
if false { // color intensity scales with damage
|
||||
color_scale = unlerp_bounded(1.0, 18.0, damage.get_num());
|
||||
} else { // color intensity scales with total KB
|
||||
// calculate the expected KB a character with 95 weight will receive
|
||||
// at 80% pre-hit
|
||||
let target_percent = 80.0;
|
||||
let target_weight = 95.0;
|
||||
let percent_component: f32;
|
||||
if fkb.get_int() > 0 {
|
||||
percent_component = (10.0 + fkb.get_int() as f32) * 0.1 * (1.0 + fkb.get_int() as f32 * 0.5);
|
||||
} else {
|
||||
percent_component = (target_percent + damage.get_num()) * 0.1 *
|
||||
(1.0 + damage.get_num() * 0.5);
|
||||
}
|
||||
let weight_component: f32 = 200.0 / (target_weight + 100.0);
|
||||
let kb: f32 = (percent_component * weight_component * 1.4 + 18.0) *
|
||||
(kbg.get_int() as f32 * 0.01) + bkb.get_int() as f32;
|
||||
color_scale = unlerp_bounded(50.0, 200.0, kb);
|
||||
}
|
||||
// non-linear scaling to magnify
|
||||
// differences at lower values
|
||||
let color_t: f32 = 0.8 + 0.2 * color_scale.powf(0.5);
|
||||
let color = color_lerp(
|
||||
Vector3f{x: 1.0, y: 1.0, z: 1.0},
|
||||
ID_COLORS[(id.get_int() % 8) as usize],
|
||||
color_t,
|
||||
2.0
|
||||
);
|
||||
generate_hitbox_effects(&mut l2c_agent, bone, size, x, y, z, x2, y2, z2, color);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
#[skyline::hook(replace = sv_animcmd::CATCH)]
|
||||
unsafe fn handle_catch(lua_state: u64) {
|
||||
let mut l2c_agent = L2CAgent::new(lua_state);
|
||||
|
||||
// get all necessary grabbox params
|
||||
let id = l2c_agent.pop_lua_stack(1); // int
|
||||
let joint = l2c_agent.pop_lua_stack(2); // hash40
|
||||
let size = l2c_agent.pop_lua_stack(3); // float
|
||||
let x = l2c_agent.pop_lua_stack(4); // float
|
||||
let y = l2c_agent.pop_lua_stack(5); // float
|
||||
let z = l2c_agent.pop_lua_stack(6); // float
|
||||
let x2 = l2c_agent.pop_lua_stack(7); // float or void
|
||||
let y2 = l2c_agent.pop_lua_stack(8); // float or void
|
||||
let z2 = l2c_agent.pop_lua_stack(9); // float or void
|
||||
|
||||
original!()(lua_state);
|
||||
|
||||
if menu.HITBOX_VIS && is_training_mode() {
|
||||
generate_hitbox_effects(&mut l2c_agent, joint, size, x, y, z, x2, y2, z2, ID_COLORS[(id.get_int() + 3 % 8) as usize]);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn is_shielding(module_accessor: *mut BattleObjectModuleAccessor) -> bool {
|
||||
let status_kind = StatusModule::status_kind(module_accessor) as i32;
|
||||
(FIGHTER_STATUS_KIND_GUARD_ON..=FIGHTER_STATUS_KIND_GUARD_OFF).contains(&status_kind)
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
#[skyline::hook(replace = AttackModule::clear_all)]
|
||||
pub unsafe fn handle_clear_all(module_accessor: *mut BattleObjectModuleAccessor) {
|
||||
if is_training_mode() {
|
||||
// only if we're not shielding
|
||||
if !is_shielding(module_accessor) {
|
||||
EffectModule::kill_kind(module_accessor, Hash40{hash: hash40("sys_shield")}, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
original!()(module_accessor);
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
#[skyline::hook(replace = GrabModule::set_rebound)]
|
||||
pub unsafe fn handle_set_rebound(module_accessor: *mut BattleObjectModuleAccessor, rebound: bool) {
|
||||
if is_training_mode() && rebound == false {
|
||||
// only if we're not shielding
|
||||
if !is_shielding(module_accessor) {
|
||||
EffectModule::kill_kind(module_accessor, Hash40{hash: hash40("sys_shield")}, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
original!()(module_accessor, rebound);
|
||||
}
|
||||
|
||||
pub fn hitbox_visualization() {
|
||||
println!("Applying hitbox visualization mods.");
|
||||
skyline::install_hook!(handle_attack);
|
||||
skyline::install_hook!(handle_catch);
|
||||
skyline::install_hook!(handle_clear_all);
|
||||
skyline::install_hook!(handle_set_rebound);
|
||||
}
|
78
src/lib.rs
78
src/lib.rs
|
@ -1,30 +1,66 @@
|
|||
#![feature(proc_macro_hygiene)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![feature(with_options)]
|
||||
|
||||
use skyline::{hook, install_hook};
|
||||
mod hitbox_visualizer;
|
||||
mod common;
|
||||
|
||||
extern "C" fn test() -> u32 {
|
||||
2
|
||||
use smash::hash40;
|
||||
use smash::lib::lua_const::{*};
|
||||
use smash::lib::{self, L2CAgent, L2CValue};
|
||||
use smash::app::{self};
|
||||
use smash::app::lua_bind::{*};
|
||||
use smash::app::sv_animcmd::{self};
|
||||
use smash::app::sv_system::{self};
|
||||
use skyline::libc::{size_t, c_int, c_void, strlen};
|
||||
use smash::Result;
|
||||
use skyline::nn;
|
||||
use skyline::patching::patch_data_from_text;
|
||||
use skyline::{from_c_str, c_str};
|
||||
use std::fs;
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
#[skyline::hook(replace = nn::ro::LoadModule)]
|
||||
pub unsafe fn handle_load_module(
|
||||
p_out_module: *mut skyline::nn::ro::Module,
|
||||
p_image: *const c_void,
|
||||
buffer: *mut c_void,
|
||||
buffer_size: size_t,
|
||||
flag: c_int) -> Result {
|
||||
|
||||
let ret = original!()(p_out_module, p_image, buffer, buffer_size, flag);
|
||||
|
||||
let name = from_c_str(&(*p_out_module).Name as *const u8);
|
||||
println!("[handleLoadModule] NRO name: {}\n", name);
|
||||
let text_start = (*(*p_out_module).ModuleObject).module_base;
|
||||
println!("Module base: {}\n", text_start);
|
||||
if name.starts_with("common") {
|
||||
println!("Is common!");
|
||||
// raw const_value_table is at : 0x635b70
|
||||
let fighter_status_kind_fall : u64 = 0x8ee6c39e9be4f0b5;
|
||||
let res = match patch_data_from_text(text_start as *const u8, 0x6362b8, &fighter_status_kind_fall) {
|
||||
Ok(v) => format!("Patched!"),
|
||||
Err(e) => format!("Error patching with e: {}", e)
|
||||
};
|
||||
|
||||
println!("{}", res);
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
#[hook(replace = test)]
|
||||
fn test_replacement() -> u32 {
|
||||
|
||||
let original_test = original!();
|
||||
|
||||
let val = original_test();
|
||||
|
||||
println!("[override] original value: {}", val); // 2
|
||||
|
||||
val + 1
|
||||
}
|
||||
|
||||
#[skyline::main(name = "skyline_rs_template")]
|
||||
#[skyline::main(name = "test")]
|
||||
pub fn main() {
|
||||
println!("Hello from Skyline Rust Plugin!");
|
||||
println!("Training modpack initialized.");
|
||||
hitbox_visualizer::hitbox_visualization();
|
||||
|
||||
install_hook!(test_replacement);
|
||||
println!("OpenMode_Write: {} {}", nn::fs::OpenMode_OpenMode_Write, nn::fs::OpenMode_OpenMode_Write as i32);
|
||||
let buffer = format!("{:x}", &common::menu as *const _ as u64);
|
||||
println!("Writing training_modpack.log with {}...\n", buffer);
|
||||
|
||||
let x = test();
|
||||
|
||||
println!("[main] test returned: {}", x); // 3
|
||||
// skyline::install_hook!(handle_load_module);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue