1
0
Fork 0
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:
jugeeya 2020-04-30 16:13:49 -07:00
parent 587da8f9ef
commit 8ab1d8a0d8
5 changed files with 516 additions and 22 deletions

View file

@ -1,5 +1,5 @@
[package] [package]
name = "skyline_rs_template" name = "training_modpack"
version = "0.1.0" version = "0.1.0"
authors = ["jam1garner <jam1.mcleod@hotmail.com>"] authors = ["jam1garner <jam1.mcleod@hotmail.com>"]
edition = "2018" edition = "2018"
@ -17,3 +17,6 @@ panic = "abort"
[profile.release] [profile.release]
panic = "abort" panic = "abort"
lto = true lto = true
[package.metadata.skyline]
titleid = "01006A800016E000"

93
src/common/consts.rs Normal file
View 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
View 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;
// }
// }

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

View file

@ -1,30 +1,66 @@
#![feature(proc_macro_hygiene)] #![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 { use smash::hash40;
2 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);
} }
#[hook(replace = test)] ret
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() { 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(); // skyline::install_hook!(handle_load_module);
println!("[main] test returned: {}", x); // 3
} }