1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-03-14 02:16:10 +00:00

Merge pull request #14 from TheSmartKid/master

Code cleanup and improved hitbox visualization
This commit is contained in:
jugeeya 2019-05-28 18:19:39 -07:00 committed by GitHub
commit bf095421ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1000 additions and 892 deletions

View file

@ -3,17 +3,17 @@
#include <switch.h>
namespace app::sv_animcmd
{
extern void frame(u64, float) asm("_ZN3app10sv_animcmd5frameEP9lua_Statef") LINKABLE;
extern void is_excute(u64) asm("_ZN3app10sv_animcmd9is_excuteEP9lua_State") LINKABLE;
extern u64 ATTACK(u64) asm("_ZN3app10sv_animcmd6ATTACKEP9lua_State") LINKABLE;
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
namespace app::sv_animcmd {
extern void wait(u64, float) asm("_ZN3app10sv_animcmd4waitEP9lua_Statef") LINKABLE;
extern void frame(u64, float) asm("_ZN3app10sv_animcmd5frameEP9lua_Statef") LINKABLE;
extern void is_excute(u64) asm("_ZN3app10sv_animcmd9is_excuteEP9lua_State") LINKABLE;
extern u64 ATTACK(u64) asm("_ZN3app10sv_animcmd6ATTACKEP9lua_State") LINKABLE;
extern u64 CATCH(u64) asm("_ZN3app10sv_animcmd5CATCHEP9lua_State") LINKABLE;
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
extern u64 EFFECT_FOLLOW_NO_SCALE(u64) asm("_ZN3app10sv_animcmd22EFFECT_FOLLOW_NO_SCALEEP9lua_State") LINKABLE;
extern u64 LAST_EFFECT_SET_COLOR(u64) asm("_ZN3app10sv_animcmd21LAST_EFFECT_SET_COLOREP9lua_State") LINKABLE;
extern u64 LAST_EFFECT_SET_RATE(u64) asm("_ZN3app10sv_animcmd20LAST_EFFECT_SET_RATEEP9lua_State") LINKABLE;
extern u64 EFFECT(u64) asm("_ZN3app10sv_animcmd6EFFECTEP9lua_State") LINKABLE;
extern u64 EFFECT_FOLLOW_NO_SCALE(u64) asm("_ZN3app10sv_animcmd22EFFECT_FOLLOW_NO_SCALEEP9lua_State") LINKABLE;
extern u64 LAST_EFFECT_SET_COLOR(u64) asm("_ZN3app10sv_animcmd21LAST_EFFECT_SET_COLOREP9lua_State") LINKABLE;
extern u64 LAST_EFFECT_SET_RATE(u64) asm("_ZN3app10sv_animcmd20LAST_EFFECT_SET_RATEEP9lua_State") LINKABLE;
}
#endif // ACMD_IMPORTS_H
#endif // ACMD_IMPORTS_H

View file

@ -5,201 +5,229 @@
#include "acmd_imports.hpp"
#include "l2c_imports.hpp"
#include "lua_helper.hpp"
#include <initializer_list>
using namespace lib;
u64 load_module(u64 module_accessor, u64 module_offset) {
return LOAD64(module_accessor + module_offset);
return LOAD64(module_accessor + module_offset);
}
void* load_module_impl(u64 module, u64 function_offset) {
u64 function_impl = LOAD64(module) + function_offset;
return (void*) LOAD64(function_impl);
}
namespace app::sv_system
{
u64 battle_object_module_accessor(u64) asm("_ZN3app9sv_system29battle_object_module_accessorEP9lua_State") LINKABLE;
u64 function_impl = LOAD64(module) + function_offset;
return (void*) LOAD64(function_impl);
}
namespace app::sv_math {
int rand(u64 hash, int endIndex) asm("_ZN3app7sv_math4randEN3phx6Hash40Ei") LINKABLE;
int rand(u64, int) asm("_ZN3app7sv_math4randEN3phx6Hash40Ei") LINKABLE;
}
namespace app::lua_bind
{
namespace AttackModule {
void clear_all(u64) asm("_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
namespace ControlModule {
bool check_button_on(u64, int) asm("_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
}
namespace EffectModule {
// boma, effect, joint, pos, rot, size, random_pos, random_rot, NO_SCALE?, attr?, unkint1, unkint2
uint req_on_joint(u64, u64, u64, const Vector3f*, const Vector3f*, float a6, const Vector3f*, const Vector3f*, bool, uint, int, int)
asm("_ZN3app8lua_bind31EffectModule__req_on_joint_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40ES4_RKNS3_8Vector3fES7_fS7_S7_bjii") LINKABLE;
void kill_kind(u64, u64, bool, bool)
asm("_ZN3app8lua_bind28EffectModule__kill_kind_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Ebb") LINKABLE;
}
namespace FighterManager {
u64 get_fighter_information(u64, int) asm("_ZN3app8lua_bind44FighterManager__get_fighter_information_implEPNS_14FighterManagerENS_14FighterEntryIDE") LINKABLE;
}
namespace FighterInformation {
bool is_operation_cpu(u64) asm("_ZN3app8lua_bind41FighterInformation__is_operation_cpu_implEPNS_18FighterInformationE") LINKABLE;
}
namespace MotionModule {
float frame(u64) asm("_ZN3app8lua_bind24MotionModule__frame_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
u64 motion_kind(u64) asm("_ZN3app8lua_bind30MotionModule__motion_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
namespace PostureModule {
float lr(u64) asm("_ZN3app8lua_bind22PostureModule__lr_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float pos_x(u64) asm("_ZN3app8lua_bind25PostureModule__pos_x_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float pos_y(u64) asm("_ZN3app8lua_bind25PostureModule__pos_y_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float set_pos(u64, const Vector3f*) asm("_ZN3app8lua_bind27PostureModule__set_pos_implEPNS_26BattleObjectModuleAccessorERKN3phx8Vector3fE") LINKABLE;
}
namespace StatusModule {
u64 change_status_request_from_script(u64, int, bool) asm("_ZN3app8lua_bind52StatusModule__change_status_request_from_script_implEPNS_26BattleObjectModuleAccessorEib") LINKABLE;
int status_kind(u64) asm("_ZN3app8lua_bind30StatusModule__status_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
int situation_kind(u64) asm("_ZN3app8lua_bind33StatusModule__situation_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
namespace WorkModule {
// PT crashes if this doesn't return a bool?
bool get_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__get_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
int get_param_int(u64, u64, u64) asm("_ZN3app8lua_bind30WorkModule__get_param_int_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
void inc_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__inc_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
}
namespace app::sv_system {
u64 battle_object(u64) asm("_ZN3app9sv_system13battle_objectEP9lua_State") LINKABLE;
u64 battle_object_module_accessor(u64) asm("_ZN3app9sv_system29battle_object_module_accessorEP9lua_State") LINKABLE;
u8 battle_object_category(u64) asm("_ZN3app9sv_system22battle_object_categoryEP9lua_State") LINKABLE;
int battle_object_kind(u64) asm("_ZN3app9sv_system18battle_object_kindEP9lua_State") LINKABLE;
}
struct ACMD
{
L2CAgent* l2c_agent;
u64 module_accessor;
namespace app::lua_bind {
namespace AttackModule {
void clear_all(u64) asm("_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
ACMD(L2CAgent* agent) {
l2c_agent = agent;
module_accessor = app::sv_system::battle_object_module_accessor(l2c_agent->lua_state_agent);
}
namespace ControlModule {
bool check_button_on(u64, int) asm("_ZN3app8lua_bind35ControlModule__check_button_on_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
}
void frame(float f) {
app::sv_animcmd::frame(l2c_agent->lua_state_agent, f);
l2c_agent->clear_lua_stack();
}
namespace EffectModule {
// boma, effect, joint, pos, rot, size, random_pos, random_rot, NO_SCALE?, attr?, unkint1, unkint2
uint req_on_joint(u64, u64, u64, const Vector3f*, const Vector3f*, float a6, const Vector3f*, const Vector3f*, bool, uint, int, int)
asm("_ZN3app8lua_bind31EffectModule__req_on_joint_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40ES4_RKNS3_8Vector3fES7_fS7_S7_bjii") LINKABLE;
bool is_excute() {
app::sv_animcmd::is_excute(l2c_agent->lua_state_agent);
L2CValue is_excute;
l2c_agent->get_lua_stack(1, &is_excute);
bool excute = is_excute.raw;
l2c_agent->clear_lua_stack();
return excute;
}
void kill_kind(u64, u64, bool, bool) asm("_ZN3app8lua_bind28EffectModule__kill_kind_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Ebb") LINKABLE;
}
void wrap( u64 (*acmd_func)(u64), std::initializer_list<L2CValue> list )
{
l2c_agent->clear_lua_stack();
for( L2CValue elem : list )
l2c_agent->push_lua_stack(&elem);
namespace FighterManager {
u64 get_fighter_information(u64, int) asm("_ZN3app8lua_bind44FighterManager__get_fighter_information_implEPNS_14FighterManagerENS_14FighterEntryIDE") LINKABLE;
}
acmd_func(l2c_agent->lua_state_agent);
l2c_agent->clear_lua_stack();
}
namespace FighterInformation {
bool is_operation_cpu(u64) asm("_ZN3app8lua_bind41FighterInformation__is_operation_cpu_implEPNS_18FighterInformationE") LINKABLE;
}
void ATTACK(
u64 i1,
u64 i2,
u64 h1,
float f1,
u64 i3,
u64 i4,
u64 i5,
u64 i6,
float f2,
float f3,
float f4,
float f5,
//void,
//void,
//void,
float f6,
float f7,
u64 i7,
u64 i8,
u64 i9,
u64 i10,
float f8,
u64 i11,
u64 i12,
u64 i13,
u64 i14,
u64 i15,
u64 i16,
u64 i17,
u64 i18,
u64 i19,
u64 i20,
u64 h2,
u64 i21,
u64 i22,
u64 i23
) {
L2CValue hitbox_params[36] = {
L2CValue(i1), // ID
L2CValue(i2), // Unk
L2CValue(h1), // Joint
L2CValue(f1), // Damage
L2CValue(i3), // Angle
L2CValue(i4), // KBG
L2CValue(i5), // WBKB
L2CValue(i6), // BKB
L2CValue(f2), // Size
L2CValue(f3), // X
L2CValue(f4), // Y
L2CValue(f5), // Z
L2CValue("void"), // X2
L2CValue("void"), // Y2
L2CValue("void"), // Z2
L2CValue(f6), // Hitlag
L2CValue(f7), // SDI
L2CValue(i7),
L2CValue(i8),
L2CValue(i9),
L2CValue(i10),
L2CValue(f8),
L2CValue(i11),
L2CValue(i12),
L2CValue(i13),
L2CValue(i14),
L2CValue(i15),
L2CValue(i16),
L2CValue(i17),
L2CValue(i18),
L2CValue(i19),
L2CValue(i20),
L2CValue(h2),
L2CValue(i21),
L2CValue(i22),
L2CValue(i23)
};
namespace MotionModule {
float frame(u64) asm("_ZN3app8lua_bind24MotionModule__frame_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
u64 motion_kind(u64) asm("_ZN3app8lua_bind30MotionModule__motion_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
for (size_t i = 0; i < 36; i++)
l2c_agent->push_lua_stack(&hitbox_params[i]);
namespace PostureModule {
float lr(u64) asm("_ZN3app8lua_bind22PostureModule__lr_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float pos_x(u64) asm("_ZN3app8lua_bind25PostureModule__pos_x_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float pos_y(u64) asm("_ZN3app8lua_bind25PostureModule__pos_y_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
float set_pos(u64, const Vector3f*) asm("_ZN3app8lua_bind27PostureModule__set_pos_implEPNS_26BattleObjectModuleAccessorERKN3phx8Vector3fE") LINKABLE;
}
app::sv_animcmd::ATTACK(l2c_agent->lua_state_agent);
namespace StatusModule {
u64 change_status_request_from_script(u64, int, bool) asm("_ZN3app8lua_bind52StatusModule__change_status_request_from_script_implEPNS_26BattleObjectModuleAccessorEib") LINKABLE;
int status_kind(u64) asm("_ZN3app8lua_bind30StatusModule__status_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
int situation_kind(u64) asm("_ZN3app8lua_bind33StatusModule__situation_kind_implEPNS_26BattleObjectModuleAccessorE") LINKABLE;
}
l2c_agent->clear_lua_stack();
}
namespace WorkModule {
float get_float(u64, int) asm("_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
bool get_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__get_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE; // this function must return a bool, otherwise Pokemon Trainer fails to load
void inc_int(u64, int) asm("_ZN3app8lua_bind24WorkModule__inc_int_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
float get_param_float(u64, u64, u64) asm("_ZN3app8lua_bind32WorkModule__get_param_float_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
int get_param_int(u64, u64, u64) asm("_ZN3app8lua_bind30WorkModule__get_param_int_implEPNS_26BattleObjectModuleAccessorEmm") LINKABLE;
void on_flag(u64, int) asm("_ZN3app8lua_bind24WorkModule__on_flag_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
void off_flag(u64, int) asm("_ZN3app8lua_bind25WorkModule__off_flag_implEPNS_26BattleObjectModuleAccessorEi") LINKABLE;
float set_float(u64, float, int) asm("_ZN3app8lua_bind26WorkModule__set_float_implEPNS_26BattleObjectModuleAccessorEfi") LINKABLE;
int set_int(u64, int, int) asm("_ZN3app8lua_bind24WorkModule__set_int_implEPNS_26BattleObjectModuleAccessorEii") LINKABLE;
}
}
struct ACMD {
L2CAgent* l2c_agent;
u64 module_accessor;
ACMD(L2CAgent* agent) {
l2c_agent = agent;
module_accessor = app::sv_system::battle_object_module_accessor(l2c_agent->lua_state_agent);
}
void frame(float f) {
l2c_agent->clear_lua_stack();
L2CValue frame_val(f);
l2c_agent->push_lua_stack(&frame_val);
app::sv_animcmd::frame(l2c_agent->lua_state_agent, f);
l2c_agent->clear_lua_stack();
}
void wait(float f) {
l2c_agent->clear_lua_stack();
L2CValue frame_val(f);
l2c_agent->push_lua_stack(&frame_val);
app::sv_animcmd::wait(l2c_agent->lua_state_agent, f);
l2c_agent->clear_lua_stack();
}
bool is_excute() {
l2c_agent->clear_lua_stack();
app::sv_animcmd::is_excute(l2c_agent->lua_state_agent);
L2CValue is_excute;
l2c_agent->get_lua_stack(1, &is_excute);
bool excute = (bool)(is_excute);
l2c_agent->clear_lua_stack();
return excute;
}
void wrap(u64 (*acmd_func)(u64), std::initializer_list<L2CValue> list) {
l2c_agent->clear_lua_stack();
for (L2CValue elem : list)
l2c_agent->push_lua_stack(&elem);
acmd_func(l2c_agent->lua_state_agent);
l2c_agent->clear_lua_stack();
}
void ATTACK(
u64 i1, // ID
u64 i2, // Part
u64 h1, // Bone
float f1, // Damage
u64 i3, // Angle
u64 i4, // KBG
u64 i5, // FKB
u64 i6, // BKB
float f2, // Size
float f3, // X
float f4, // Y
float f5, // Z
// X2
// Y2
// Z2
float f6, // Hitlag
float f7, // SDI
u64 i7, // Clang/Rebound
u64 i8, // Facing Restriction
u64 i9, // Fixed Weight
u64 i10, // Shield Damage
float f8, // Trip Chance
u64 i11, // Rehit Rate
u64 i12, // Reflectable
u64 i13, // Absorbable
u64 i14, // Flinchless
u64 i15, // Disable Hitlag
u64 i16, // Direct
u64 i17, // Ground/Air
u64 i18, // Hit Bits
u64 i19, // Collision Bits
u64 i20, // Friendly Fire
u64 h2, // Effect
u64 i21, // SFX Level
u64 i22, // SFX Type
u64 i23) { // Move Type
wrap(app::sv_animcmd::ATTACK, {
L2CValue(i1), L2CValue(i2), L2CValue(h1), L2CValue(f1),
L2CValue(i3), L2CValue(i4), L2CValue(i5), L2CValue(i6),
L2CValue(f2), L2CValue(f3), L2CValue(f4), L2CValue(f5),
L2CValue(), L2CValue(), L2CValue(), L2CValue(f6),
L2CValue(f7), L2CValue(i7), L2CValue(i8), L2CValue(i9),
L2CValue(i10), L2CValue(f8), L2CValue(i11), L2CValue(i12),
L2CValue(i13), L2CValue(i14), L2CValue(i15), L2CValue(i16),
L2CValue(i17), L2CValue(i18), L2CValue(i19), L2CValue(i20),
L2CValue(h2), L2CValue(i21), L2CValue(i22), L2CValue(i23)
});
}
void ATTACK(
u64 i1, // ID
u64 i2, // Part
u64 h1, // Bone
float f1, // Damage
u64 i3, // Angle
u64 i4, // KBG
u64 i5, // FKB
u64 i6, // BKB
float f2, // Size
float f3, // X
float f4, // Y
float f5, // Z
float fX2, // X2
float fY2, // Y2
float fZ2, // Z2
float f6, // Hitlag
float f7, // SDI
u64 i7, // Clang/Rebound
u64 i8, // Facing Restriction
u64 i9, // Fixed Weight
u64 i10, // Shield Damage
float f8, // Trip Chance
u64 i11, // Rehit Rate
u64 i12, // Reflectable
u64 i13, // Absorbable
u64 i14, // Flinchless
u64 i15, // Disable Hitlag
u64 i16, // Direct
u64 i17, // Ground/Air
u64 i18, // Hit Bits
u64 i19, // Collision Bits
u64 i20, // Friendly Fire
u64 h2, // Effect
u64 i21, // SFX Level
u64 i22, // SFX Type
u64 i23) { // Move Type
wrap(app::sv_animcmd::ATTACK, {
L2CValue(i1), L2CValue(i2), L2CValue(h1), L2CValue(f1),
L2CValue(i3), L2CValue(i4), L2CValue(i5), L2CValue(i6),
L2CValue(f2), L2CValue(f3), L2CValue(f4), L2CValue(f5),
L2CValue(fX2), L2CValue(fY2), L2CValue(fZ2), L2CValue(f6),
L2CValue(f7), L2CValue(i7), L2CValue(i8), L2CValue(i9),
L2CValue(i10), L2CValue(f8), L2CValue(i11), L2CValue(i12),
L2CValue(i13), L2CValue(i14), L2CValue(i15), L2CValue(i16),
L2CValue(i17), L2CValue(i18), L2CValue(i19), L2CValue(i20),
L2CValue(h2), L2CValue(i21), L2CValue(i22), L2CValue(i23)
});
}
};
#endif // ACMD_WRAPPER_H
#endif // ACMD_WRAPPER_H

View file

@ -1,5 +1,6 @@
#ifndef CONST_VALUE_TABLE_H
#define CONST_VALUE_TABLE_H
#define LUA_SCRIPT_LINE_MAX lua_const("LUA_SCRIPT_LINE_MAX")
#define LUA_SCRIPT_LINE_SYSTEM lua_const("LUA_SCRIPT_LINE_SYSTEM")
#define LUA_SCRIPT_LINE_SYSTEM_POST lua_const("LUA_SCRIPT_LINE_SYSTEM_POST")
@ -15877,4 +15878,5 @@
#define ITEM_ZOROARK_INSTANCE_WORK_INT_TARGET_STATE lua_const("ITEM_ZOROARK_INSTANCE_WORK_INT_TARGET_STATE")
#define ITEM_ZOROARK_INSTANCE_WORK_FLOAT_THROWUP_LR lua_const("ITEM_ZOROARK_INSTANCE_WORK_FLOAT_THROWUP_LR")
#define ITEM_ZOROARK_INSTANCE_WORK_FLAG_THROW_UP_GRAVITY_START lua_const("ITEM_ZOROARK_INSTANCE_WORK_FLAG_THROW_UP_GRAVITY_START")
#endif // CONST_VALUE_TABLE_H

View file

@ -2,7 +2,6 @@
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
#ifndef CRC32_H
#define CRC32_H
@ -55,8 +54,7 @@ const uint32_t crc32_tab[] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t crc32_part(const void *buf, size_t size, uint32_t crc)
{
uint32_t crc32_part(const void *buf, size_t size, uint32_t crc) {
const uint8_t* p = (const uint8_t*)buf;
crc = crc ^ ~0U;
while (size--)
@ -64,8 +62,7 @@ uint32_t crc32_part(const void *buf, size_t size, uint32_t crc)
return crc ^ ~0U;
}
uint32_t crc32(const void *buf, size_t size)
{
uint32_t crc32(const void *buf, size_t size) {
const uint8_t* p = (const uint8_t*)buf;
uint32_t crc;
crc = ~0U;
@ -74,10 +71,9 @@ uint32_t crc32(const void *buf, size_t size)
return crc ^ ~0U;
}
uint64_t hash40(const char* data)
{
uint64_t hash40(const char* data) {
size_t len = strlen(data);
return crc32(data, len) | (len & 0xFF) << 32;
return crc32(data, len) | (len & 0xFF) << 32;
}
#endif // CRC32_H

View file

@ -1,7 +1,12 @@
#include "l2c.hpp"
#include "saltysd_helper.hpp"
#include <math.h>
#include "useful.h"
#include "useful_visual.h"
#include "l2c_imports.hpp"
#include "acmd_imports.hpp"
#include "acmd_wrapper.hpp"
#include "saltysd_helper.hpp"
#include "const_value_table.h"
#include "taunt_toggles.h"
using namespace lib;
@ -10,138 +15,159 @@ using namespace app::sv_animcmd;
void (*AttackModule_set_attack_lua_state)(u64, u64);
Vector3f id_colors[8] = {
{1.0f, 0.0f, 0.0f}, {0.7843f, 0.3529f, 1.0f},
{1.0f, 0.7843f, 0.7843f}, {0.0f, 1.0f, 0.8431f},
{1.0f, 0.4706f, 0.0f}, {0.7843f, 0.7059f, 0.0f},
{0.7843f, 0.0f, 1.0f}, {0.3765f, 0.2863f, 0.5294f},
Vector3f ID_COLORS[8] = { // used to tint the hitbox effects -- make sure that at least one component is equal to 1.0
{ 1.0f, 0.0f, 0.0f }, // #ff0000 (red)
{ 1.0f, 0.4f, 0.0f }, // #ff9900 (orange)
{ 0.8f, 1.0f, 0.0f }, // #ccff00 (yellow)
{ 0.2f, 1.0f, 0.2f }, // #00ff33 (green)
{ 0.0f, 0.8f, 1.0f }, // #00ccff (sky blue)
{ 0.4f, 0.4f, 1.0f }, // #6666ff (blue)
{ 0.8f, 0.0f, 1.0f }, // #cc00ff (purple)
{ 1.0f, 0.2f, 0.8f }, // #ff33cc (pink)
};
int MAX_EFFECTS_PER_HITBOX = 16; // max # of circles drawn for an extended hitbox
namespace app::lua_bind::AttackModule {
// Clear graphics every time we clear all hitboxes
void clear_all_replace(u64 module_accessor) {
if (is_training_mode()) {
// Only if we're not shielding
int status_kind = StatusModule::status_kind(module_accessor);
if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) {
Hash40 shieldEffectHash = {.hash = 0xAFAE75F05LL};
EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1);
}
}
// clear graphics every time we clear all hitboxes
void clear_all_replace(u64 module_accessor) {
if (is_training_mode()) {
// only if we're not shielding
int status_kind = StatusModule::status_kind(module_accessor);
if (!(status_kind >= FIGHTER_STATUS_KIND_GUARD_ON && status_kind <= FIGHTER_STATUS_KIND_GUARD_OFF)) {
Hash40 shieldEffectHash = { .hash = 0xAFAE75F05LL };
EffectModule::kill_kind(module_accessor, shieldEffectHash.hash, 0, 1);
}
}
// call original AttackModule::clear_all_impl
u64 attack_module = load_module(module_accessor, 0xA0);
void (*clear_all)(u64) = (void(*)(u64))(load_module_impl(attack_module, 0x50));
// call original AttackModule::clear_all_impl
u64 attack_module = load_module(module_accessor, 0xA0);
void (*clear_all)(u64) = (void(*)(u64))(load_module_impl(attack_module, 0x50));
return clear_all(attack_module);
}
return clear_all(attack_module);
}
}
void generate_hitbox_effects(L2CAgent *l2c_agent, L2CValue *id, L2CValue *bone,
L2CValue *size, L2CValue *x, L2CValue *y,
L2CValue *z, L2CValue *x2, L2CValue *y2,
L2CValue *z2) {
Vector3f color = id_colors[id->raw % 8];
L2CValue red(color.x);
L2CValue green(color.y);
L2CValue blue(color.z);
void generate_hitbox_effects(L2CAgent *l2c_agent, L2CValue *bone, L2CValue *size,
L2CValue *x, L2CValue *y, L2CValue *z, L2CValue *x2, L2CValue *y2, L2CValue *z2,
Vector3f *color) {
L2CValue red(color->x);
L2CValue green(color->y);
L2CValue blue(color->z);
float size_mult = 19.0f / 200.0f;
Hash40 shield_effect_hash = { .hash = 0xAFAE75F05LL };
float sizeMult = 19.0 / 200.0;
Hash40 shieldEffectHash = {.hash = 0xAFAE75F05LL};
L2CValue shieldEffect(shield_effect_hash.hash);
L2CValue x_rot(0.0f);
L2CValue y_rot(0.0f);
L2CValue z_rot(0.0f);
L2CValue terminate(true);
L2CValue effect_size((float)size->raw_float * size_mult);
L2CValue shieldEffect(shieldEffectHash.hash);
L2CValue xRot(0.0f);
L2CValue yRot(0.0f);
L2CValue zRot(0.0f);
L2CValue terminate(true);
L2CValue effectSize((float)size->raw_float * sizeMult);
L2CValue rate(8.0f);
L2CValue rate(8.0f);
float x_dist, y_dist, z_dist;
int n_effects;
if (x2->type != L2C_void && y2->type != L2C_void && z2->type != L2C_void) { // extended hitbox
x_dist = x2->raw_float - x->raw_float;
y_dist = y2->raw_float - y->raw_float;
z_dist = z2->raw_float - z->raw_float;
float dist = sqrtf(x_dist * x_dist + y_dist * y_dist + z_dist * z_dist);
n_effects = (int)ceilf(dist / (size->raw_float * 1.75f)) + 1; // just enough effects to form a continuous line
if (n_effects < 2)
n_effects = 2;
if (n_effects > MAX_EFFECTS_PER_HITBOX)
n_effects = MAX_EFFECTS_PER_HITBOX;
} else { // non-extended hitbox
x_dist = y_dist = z_dist = 0;
n_effects = 1;
}
// Extended Hitboxes if x2, y2, z2 are not L2CValue::nil
int num_effects;
if (x2->type != L2C_void && y2->type != L2C_void && z2->type != L2C_void) {
num_effects = 4;
} else {
*x2 = *x;
*y2 = *y;
*z2 = *z;
num_effects = 1;
}
for (int i = 0; i < n_effects; i++) {
float t = n_effects <= 1 ? 0 : (float)i / (n_effects - 1);
L2CValue x_curr(x->raw_float + x_dist * t);
L2CValue y_curr(y->raw_float + y_dist * t);
L2CValue z_curr(z->raw_float + z_dist * t);
for (int i = 0; i < num_effects; i++) {
L2CValue currX(x->raw_float + ((x2->raw_float - x->raw_float) / 3 * i));
L2CValue currY(y->raw_float + ((y2->raw_float - y->raw_float) / 3 * i));
L2CValue currZ(z->raw_float + ((z2->raw_float - z->raw_float) / 3 * i));
ACMD acmd(l2c_agent);
acmd.wrap(EFFECT_FOLLOW_NO_SCALE, { shieldEffect, *bone, x_curr, y_curr, z_curr, x_rot, y_rot, z_rot, effect_size, terminate });
ACMD acmd(l2c_agent);
acmd.wrap(EFFECT_FOLLOW_NO_SCALE,
{shieldEffect, *bone, currX, currY, currZ, xRot, yRot, zRot, effectSize, terminate}
);
// set to hitbox ID color
acmd.wrap(LAST_EFFECT_SET_COLOR, { red, green, blue });
// Set to hitbox ID color
acmd.wrap(LAST_EFFECT_SET_COLOR, {red, green, blue});
// Speed up animation by rate to remove pulsing effect
// LAST_EFFECT_SET_RATE(Rate)
acmd.wrap(LAST_EFFECT_SET_RATE, {rate});
}
// speed up animation by rate to remove pulsing effect
acmd.wrap(LAST_EFFECT_SET_RATE, { rate });
}
}
namespace app::sv_animcmd {
void ATTACK_replace(u64 a1) {
// Instantiate our own L2CAgent with the given lua_State
L2CAgent l2c_agent;
l2c_agent.L2CAgent_constr(a1);
void ATTACK_replace(u64 a1) {
// instantiate our own L2CAgent with the given lua_State
L2CAgent l2c_agent;
l2c_agent.L2CAgent_constr(a1);
// Get all necessary hitbox params
L2CValue id, bone, damage, angle, kbg, wkb, bkb, size, x, y, z, x2, y2, z2;
l2c_agent.get_lua_stack(1, &id);
l2c_agent.get_lua_stack(3, &bone);
l2c_agent.get_lua_stack(4, &damage);
l2c_agent.get_lua_stack(5, &angle);
l2c_agent.get_lua_stack(6, &kbg);
l2c_agent.get_lua_stack(7, &wkb);
l2c_agent.get_lua_stack(8, &bkb);
l2c_agent.get_lua_stack(9, &size);
l2c_agent.get_lua_stack(10, &x);
l2c_agent.get_lua_stack(11, &y);
l2c_agent.get_lua_stack(12, &z);
l2c_agent.get_lua_stack(13, &x2);
l2c_agent.get_lua_stack(14, &y2);
l2c_agent.get_lua_stack(15, &z2);
// get all necessary hitbox params
L2CValue id, bone, damage, angle, kbg, fkb, bkb, size, x, y, z, x2, y2, z2;
l2c_agent.get_lua_stack(1, &id); // int
l2c_agent.get_lua_stack(3, &bone); // hash40
l2c_agent.get_lua_stack(4, &damage); // float
l2c_agent.get_lua_stack(5, &angle); // int
l2c_agent.get_lua_stack(6, &kbg); // int
l2c_agent.get_lua_stack(7, &fkb); // int
l2c_agent.get_lua_stack(8, &bkb); // int
l2c_agent.get_lua_stack(9, &size); // float
l2c_agent.get_lua_stack(10, &x); // float
l2c_agent.get_lua_stack(11, &y); // float
l2c_agent.get_lua_stack(12, &z); // float
l2c_agent.get_lua_stack(13, &x2); // float or void
l2c_agent.get_lua_stack(14, &y2); // float or void
l2c_agent.get_lua_stack(15, &z2); // float or void
// original code: parse lua stack and call AttackModule::set_attack()
AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1);
// original code: parse lua stack and call AttackModule::set_attack()
AttackModule_set_attack_lua_state(LOAD64(LOAD64(a1 - 8) + 416LL), a1);
if (HITBOX_VIS && is_training_mode()) {
// Generate hitbox effect(s)
generate_hitbox_effects(&l2c_agent, &id, &bone, &size, &x, &y, &z, &x2, &y2, &z2);
}
if (HITBOX_VIS && is_training_mode()) { // generate hitbox effect(s)
float color_scale;
if (false) { // color intensity scales with damage
color_scale = unlerp_bounded(1.0f, 18.0f, damage.raw_float);
} else { // color intensity scales with total KB
// calculate the expected KB a character with 95 weight will receive at 80% pre-hit
float TARGET_PERCENT = 80.0f;
int TARGET_WEIGHT = 95;
float percent_component;
if (fkb.raw > 0) {
percent_component = (10.0f + fkb.raw) * 0.1f * (1.0f + fkb.raw * 0.5f);
} else {
percent_component = (TARGET_PERCENT + damage.raw_float) * 0.1f * (1.0f + damage.raw_float * 0.5f);
}
float weight_component = 200.0f / (TARGET_WEIGHT + 100);
float kb = (percent_component * weight_component * 1.4f + 18.0f) * (kbg.raw * 0.01f) + bkb.raw;
color_scale = unlerp_bounded(50.0f, 200.0f, kb);
}
float color_t = 0.6f + 0.4f * powf(color_scale, 0.5f); // non-linear scaling to magnify differences at lower values
Vector3f color = color_lerp({ 1.0f, 1.0f, 1.0f }, ID_COLORS[id.raw % 8], color_t);
generate_hitbox_effects(&l2c_agent, &bone, &size, &x, &y, &z, &x2, &y2, &z2, &color);
}
u64 v1, v2, i;
v1 = a1;
u64 v1, v2, i;
v1 = a1;
// original code: clear_lua_stack section
v2 = LOAD64(v1 + 16);
for (i = **(u64 **)(v1 + 32) + 16LL; v2 < i; v2 = LOAD64(v1 + 16)) {
LOAD64(v1 + 16) = v2 + 16;
*(__int32_t *)(v2 + 8) = 0;
}
LOAD64(v1 + 16) = i;
}
// original code: clear_lua_stack section
v2 = LOAD64(v1 + 16);
for (i = **(u64 **)(v1 + 32) + 16LL; v2 < i; v2 = LOAD64(v1 + 16)) {
LOAD64(v1 + 16) = v2 + 16;
*(__int32_t *)(v2 + 8) = 0;
}
LOAD64(v1 + 16) = i;
}
}
void hitbox_vis_main() {
AttackModule_set_attack_lua_state =
(void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + 0xD0 - 0x70;
SaltySD_function_replace_sym(
"_ZN3app10sv_animcmd6ATTACKEP9lua_State",
(u64)&ATTACK_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE",
(u64)&AttackModule::clear_all_replace);
}
AttackModule_set_attack_lua_state = (void (*)(u64, u64))SaltySDCore_FindSymbol("_ZN3app10sv_animcmd6ATTACKEP9lua_State") + 0xD0 - 0x70;
SaltySD_function_replace_sym(
"_ZN3app10sv_animcmd6ATTACKEP9lua_State",
(u64)&ATTACK_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind28AttackModule__clear_all_implEPNS_26BattleObjectModuleAccessorE",
(u64)&AttackModule::clear_all_replace);
}

View file

@ -1,16 +0,0 @@
#ifndef L2C_H
#define L2C_H
typedef struct Hash40
{
uint64_t hash : 40;
} Hash40;
typedef struct Vector3f
{
float x;
float y;
float z;
} Vector3f;
#endif // L2C_H

View file

@ -1,138 +1,151 @@
#ifndef L2C_IMPORTS_H
#define L2C_IMPORTS_H
#include <switch.h>
#include "l2c.hpp"
#include "lua_bind_hash.hpp"
#include <math.h>
#define LOAD64 *(u64 *)
#include "useful.h"
#include "lua_bind_hash.hpp"
u64 is_training_mode(void) asm("_ZN3app9smashball16is_training_modeEv") LINKABLE;
namespace lib
{
enum L2CVarType
{
L2C_void = 0,
L2C_bool = 1,
L2C_integer = 2,
L2C_number = 3,
L2C_pointer = 4,
L2C_table = 5,
L2C_inner_function = 6,
L2C_hash = 7,
L2C_string = 8,
};
namespace lib {
enum L2CVarType {
L2C_void = 0,
L2C_bool = 1,
L2C_integer = 2,
L2C_number = 3,
L2C_pointer = 4,
L2C_table = 5,
L2C_inner_function = 6,
L2C_hash = 7,
L2C_string = 8,
};
struct L2CTable_meta
{
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
};
typedef struct L2CTable_meta {
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
} L2CTable_meta;
struct L2CTable
{
uint32_t refcnt;
uint32_t unk;
uint64_t begin; // L2CValue*
uint64_t end; // L2CValue*
uint64_t also_end; // L2CValue*
struct L2CTable_meta meta;
uint64_t unk_ptr;
};
typedef struct L2CTable {
uint32_t refcnt;
uint32_t unk;
struct L2CInnerFunctionBase
{
uint64_t unk;
uint32_t refcnt;
} L2CInnerFunctionBase;
uint64_t begin; // L2CValue*
uint64_t end; // L2CValue*
uint64_t also_end; // L2CValue*
struct L2CTable_meta meta;
uint64_t unk_ptr;
} L2CTable;
struct L2CValue
{
uint32_t type;
uint32_t unk;
union
{
uint64_t raw;
float raw_float;
void* raw_pointer;
struct L2CTable* raw_table;
struct L2CInnerFunctionBase* raw_innerfunc;
//std::string* raw_string;
};
typedef struct L2CInnerFunctionBase {
uint64_t unk;
uint32_t refcnt;
} L2CInnerFunctionBase;
L2CValue() {}
struct L2CValue {
uint32_t type;
uint32_t unk;
union {
uint64_t raw;
float raw_float;
// void* raw_pointer;
// struct L2CTable* raw_table;
// struct L2CInnerFunctionBase* raw_innerfunc;
//std::string* raw_string;
};
L2CValue(bool val) {
type = L2C_bool;
raw = val;
}
L2CValue() {
type = L2C_void;
}
L2CValue(u64 val) {
type = L2C_integer;
raw = val;
}
L2CValue(bool val) {
type = L2C_bool;
raw = val;
}
L2CValue(float val) {
type = L2C_number;
raw_float = val;
}
L2CValue(int val) {
type = L2C_integer;
raw = val;
}
L2CValue(const char* str) {
type = L2C_void;
}
L2CValue(u64 val) {
type = L2C_integer;
raw = val;
}
};
L2CValue(float val) {
if (isnan(val)) {
type = L2C_void;
} else {
type = L2C_number;
raw_float = val;
}
}
struct L2CAgent
{
uint64_t vtable;
uint64_t lua_state_agent;
uint64_t unk10;
uint64_t unk18;
uint64_t unk20;
uint64_t unk28;
uint64_t unk30;
uint64_t unk38;
uint64_t lua_state_agentbase;
L2CValue(double val) {
if (isnan(val)) {
type = L2C_void;
} else {
type = L2C_number;
raw_float = val;
}
}
L2CAgent* L2CAgent_constr(u64 lua_state) asm("_ZN3lib8L2CAgentC2EP9lua_State") LINKABLE;
u64 push_lua_stack(L2CValue* l2c_value) asm("_ZN3lib8L2CAgent14push_lua_stackERKNS_8L2CValueE") LINKABLE;
// pop_lua_stack
// Notes:
// Actually takes three arguments, but the third is given through X8 due to how
// AArch64 treats struct pointers that are used as pass by reference to get the value.
// Thus, my current solution is to use inline ASM before using this to pass the
// last arg. This is done using asm("mov x8, %x0" : : "r"(&popped) : "x8" );, where
// popped is an L2CValue that will be populated by the function.
// FURTHERMORE, this function does NOT actually pop the stack, it only returns the value at the
// position indicated by the second argument.
// This index is either positive, meaning absolute position in the stack, or negative,
// which is more traditional, i.e. -1 is the top of the stack.
//__int64_t (*lib_L2CAgent_pop_lua_stack)(__int64_t, int);
u64 pop_lua_stack(int index) asm("_ZN3lib8L2CAgent13pop_lua_stackEi") LINKABLE;
operator bool() asm("_ZNK3lib8L2CValuecvbEv") LINKABLE;
void get_lua_stack(int index, lib::L2CValue* l2c_val) {
asm("mov x8, %x0" : : "r"(l2c_val) : "x8" );
pop_lua_stack(index);
}
void push_variadic(u64, const char*, void*) asm("_ZN3lib8L2CValue13push_variadicEmPKcRNS_7utility8VariadicE") LINKABLE;
};
u64 sv_set_function_hash(u64 (*func)(L2CAgent*, void*), u64 hash) asm("_ZN3lib8L2CAgent20sv_set_function_hashEPvN3phx6Hash40E") LINKABLE;
u64 clear_lua_stack() asm("_ZN3lib8L2CAgent15clear_lua_stackEv") LINKABLE;
};
struct L2CAgent {
uint64_t vtable;
uint64_t lua_state_agent;
uint64_t unk10;
uint64_t unk18;
uint64_t unk20;
uint64_t unk28;
uint64_t unk30;
uint64_t unk38;
uint64_t lua_state_agentbase;
bool lua_bind_get_value(u64, int*) asm("_ZN3lib18lua_bind_get_valueIiEEbmRT_") LINKABLE;
L2CAgent* L2CAgent_constr(u64 lua_state) asm("_ZN3lib8L2CAgentC2EP9lua_State") LINKABLE;
u64 push_lua_stack(L2CValue* l2c_value) asm("_ZN3lib8L2CAgent14push_lua_stackERKNS_8L2CValueE") LINKABLE;
// pop_lua_stack
// Notes:
// Actually takes three arguments, but the third is given through X8 due to how
// AArch64 treats struct pointers that are used as pass by reference to get the value.
// Thus, my current solution is to use inline ASM before using this to pass the
// last arg. This is done using asm("mov x8, %x0" : : "r"(&popped) : "x8" );, where
// popped is an L2CValue that will be populated by the function.
// FURTHERMORE, this function does NOT actually pop the stack, it only returns the value at the
// position indicated by the second argument.
// This index is either positive, meaning absolute position in the stack, or negative,
// which is more traditional, i.e. -1 is the top of the stack.
//__int64_t (*lib_L2CAgent_pop_lua_stack)(__int64_t, int);
u64 pop_lua_stack(int index) asm("_ZN3lib8L2CAgent13pop_lua_stackEi") LINKABLE;
int lua_const(const char* str) {
int val;
if (lua_bind_get_value(lua_bind_hash_str(str), &val))
return val;
else
return -1;
}
void get_lua_stack(int index, lib::L2CValue* l2c_val) {
asm("mov x8, %x0" : : "r"(l2c_val) : "x8" );
pop_lua_stack(index);
}
u64 sv_set_function_hash(u64 (*func)(L2CAgent*, void*), u64 hash) asm("_ZN3lib8L2CAgent20sv_set_function_hashEPvN3phx6Hash40E") LINKABLE;
u64 clear_lua_stack() asm("_ZN3lib8L2CAgent15clear_lua_stackEv") LINKABLE;
};
bool lua_bind_get_value(u64, int*) asm("_ZN3lib18lua_bind_get_valueIiEEbmRT_") LINKABLE;
int lua_const(const char* str) {
int val;
if (lua_bind_get_value(lua_bind_hash_str(str), &val))
return val;
else
return -1;
}
}
#endif // L2C_IMPORTS_H

View file

@ -1,97 +1,101 @@
#ifndef LUA_BIND_HASH_H
#define LUA_BIND_HASH_H
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
uint64_t lua_bind_hash(const void* data_, size_t len) {
int64_t *data = (int64_t*)data_;
size_t hash = len;
int64_t hash_add = 0x27d4eb2f165667c4;
int64_t* data_end = (int64_t *)((int64_t)data + len);
int64_t *data = (int64_t*)data_;
size_t hash = len;
int64_t hash_add = 0x27d4eb2f165667c4;
int64_t* data_end = (int64_t *)((int64_t)data + len);
uint64_t hash_vals[4] = {
0x60ea27eeadc0b5d5,
0xc2b2ae3d27d4eb4e,
0xffffffffffffffff,
0x61c8864e7a143578,
};
uint64_t hash_vals[4] = {
0x60ea27eeadc0b5d5,
0xc2b2ae3d27d4eb4e,
0xffffffffffffffff,
0x61c8864e7a143578,
};
uint64_t hash_vals_mid[4];
uint64_t hash_vals_mid[4];
const uint64_t hash_vals_end[4] = {
0x3c6ef3630bd7950e,
0x1bbcd8c2f5e54380,
0x779b185ebca87000,
0xe6c617af2a1c0000
};
const uint64_t hash_vals_end[4] = {
0x3c6ef3630bd7950e,
0x1bbcd8c2f5e54380,
0x779b185ebca87000,
0xe6c617af2a1c0000
};
const uint64_t hash_vals_end_2[4] = {
0x3f,
0x39,
0x34,
0x2e
};
const uint64_t hash_vals_end_2[4] = {
0x3f,
0x39,
0x34,
0x2e
};
const uint64_t MULT1 = 0x87bcb65480000000; // -0x784349ab80000000
const uint64_t MULT2 = 0xdef35b010f796ca9; // -0x210ca4fef0869357
const uint64_t MULT3 = 0x9e3779b185ebca87; // -0x61c8864e7a143579
const uint64_t MULT4 = 0xc2b2ae3d27d4eb4f; // -0x3d4d51c2d82b14b1
const uint64_t MULT5 = 0x93ea75a780000000; // -0x6c158a5880000000
const uint64_t MULT6 = 0x27d4eb2f165667c5;
const uint64_t ADD1 = 0x85ebca77c2b2ae63;
const uint64_t ADD2 = 0x165667b19e3779f9;
if (len >= 32) {
do {
for (int i = 0; i < 4; i++) {
hash_vals[i] += data[i] * MULT4;
hash_vals_mid[i] = hash_vals[i] >> 0x21 | hash_vals[i] * 0x80000000;
hash_vals[i] = hash_vals_mid[i] * MULT3;
}
data = data + 4;
} while (data <= data_end + -4);
uint64_t val = 0;
for (int i = 0; i < 4; i++) {
val += (hash_vals_mid[i] * hash_vals_end[i] | hash_vals[i] >> hash_vals_end_2[i]);
}
const uint64_t MULT1 = 0x87bcb65480000000; // -0x784349ab80000000
const uint64_t MULT2 = 0xdef35b010f796ca9; // -0x210ca4fef0869357
const uint64_t MULT3 = 0x9e3779b185ebca87; // -0x61c8864e7a143579
const uint64_t MULT4 = 0xc2b2ae3d27d4eb4f; // -0x3d4d51c2d82b14b1
const uint64_t MULT5 = 0x93ea75a780000000; // -0x6c158a5880000000
const uint64_t MULT6 = 0x27d4eb2f165667c5;
const uint64_t ADD1 = 0x85ebca77c2b2ae63;
const uint64_t ADD2 = 0x165667b19e3779f9;
if (len >= 32) {
do {
for (int i = 0; i < 4; i++) {
hash_vals[i] += data[i] * MULT4;
hash_vals_mid[i] = hash_vals[i] >> 0x21 | hash_vals[i] * 0x80000000;
hash_vals[i] = hash_vals_mid[i] * MULT3;
}
data = data + 4;
} while (data <= data_end + -4);
uint64_t val = 0;
for (int i = 0; i < 4; i++) {
val += (hash_vals_mid[i] * hash_vals_end[i] | hash_vals[i] >> hash_vals_end_2[i]);
}
val = (val ^ (hash_vals_mid[0] * MULT1 | hash_vals_mid[0] * MULT2 >> 0x21) * MULT3) * MULT3;
for (int i = 1; i < 4; i++) {
val = (val + ADD1 ^ (hash_vals_mid[i] * MULT1 | hash_vals_mid[i] * MULT2 >> 0x21) * MULT3) * MULT3;
}
val += ADD1;
val = (val ^ (hash_vals_mid[0] * MULT1 | hash_vals_mid[0] * MULT2 >> 0x21) * MULT3) * MULT3;
for (int i = 1; i < 4; i++) {
val = (val + ADD1 ^ (hash_vals_mid[i] * MULT1 | hash_vals_mid[i] * MULT2 >> 0x21) * MULT3) * MULT3;
}
val += ADD1;
hash_add = val;
}
hash_add = val;
}
hash += hash_add;
for (; data + 1 <= data_end; data++) {
hash = (*data * MULT5 | (*data * MULT4) >> 0x21) *
MULT3 ^ hash;
hash = (hash >> 0x25 | hash << 0x1b) * MULT3 + ADD1;
}
hash += hash_add;
for (; data + 1 <= data_end; data++) {
hash = (*data * MULT5 | (*data * MULT4) >> 0x21) * MULT3 ^ hash;
hash = (hash >> 0x25 | hash << 0x1b) * MULT3 + ADD1;
}
int32_t* data_32 = (int32_t*) data;
if ((int64_t *)(data_32 + 1) <= data_end) {
hash = (uint64_t)*data_32 * MULT3 ^ hash;
hash = (hash >> 0x29 | hash << 0x17) * MULT4 + ADD2;
data = (int64_t *)(data_32 + 1);
}
int32_t* data_32 = (int32_t*) data;
if ((int64_t *)(data_32 + 1) <= data_end) {
hash = (uint64_t)*data_32 * MULT3 ^ hash;
hash = (hash >> 0x29 | hash << 0x17) * MULT4 + ADD2;
data = (int64_t *)(data_32 + 1);
}
int8_t* data_8 = (int8_t*) data;
int8_t* data_8 = (int8_t*) data;
for (; data != data_end; data = (int64_t*)data_8) {
hash = (uint64_t)(*data_8) * MULT6 ^ hash;
hash = (hash >> 0x35 | hash << 0xb) * MULT3;
data_8++;
}
uint64_t final_hash = (hash ^ hash >> 0x21) * MULT4;
final_hash = (final_hash ^ final_hash >> 0x1d) * ADD2;
return final_hash ^ final_hash >> 0x20;
for (; data != data_end; data = (int64_t*)data_8) {
hash = (uint64_t)(*data_8) * MULT6 ^ hash;
hash = (hash >> 0x35 | hash << 0xb) * MULT3;
data_8++;
}
uint64_t final_hash = (hash ^ hash >> 0x21) * MULT4;
final_hash = (final_hash ^ final_hash >> 0x1d) * ADD2;
return final_hash ^ final_hash >> 0x20;
}
uint64_t lua_bind_hash_str(const char* str) {
return lua_bind_hash(str, strlen(str));
}
return lua_bind_hash(str, strlen(str));
}
#endif // LUA_BIND_HASH_H

View file

@ -1,8 +0,0 @@
#ifndef LUA_HELPER_H
#define LUA_HELPER_H
#include <switch.h>
#include "l2c_imports.hpp"
#endif // LUA_HELPER_H

View file

@ -1,7 +1,6 @@
#include <switch.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/iosupport.h>
@ -15,21 +14,23 @@
#include "saltysd_dynamic.h"
#include "saltysd_helper.hpp"
#include "l2c_imports.hpp"
#include "acmd_imports.hpp"
#include "script_replacement.hpp"
#include "hitbox_visualizer.hpp"
#include "script_replacement.hpp"
#include "training_mods.hpp"
extern "C" {
extern u32 __start__;
extern u32 __start__;
static char g_heap[0x8000];
static char g_heap[0x8000];
void __libnx_init(void* ctx, Handle main_thread, void* saved_lr);
void __attribute__((weak)) NORETURN __libnx_exit(int rc);
void __nx_exit(int, void*);
void __libc_fini_array(void);
void __libc_init_array(void);
void __libnx_init(void* ctx, Handle main_thread, void* saved_lr);
void __attribute__((weak)) NORETURN __libnx_exit(int rc);
void __nx_exit(int, void*);
void __libc_fini_array(void);
void __libc_init_array(void);
}
u32 __nx_applet_type = AppletType_None;
@ -38,61 +39,58 @@ Handle orig_main_thread;
void* orig_ctx;
void* orig_saved_lr;
void __libnx_init(void* ctx, Handle main_thread, void* saved_lr)
{
extern char* fake_heap_start;
extern char* fake_heap_end;
void __libnx_init(void* ctx, Handle main_thread, void* saved_lr) {
extern char* fake_heap_start;
extern char* fake_heap_end;
fake_heap_start = &g_heap[0];
fake_heap_end = &g_heap[sizeof g_heap];
orig_ctx = ctx;
orig_main_thread = main_thread;
orig_saved_lr = saved_lr;
// Call constructors.
//void __libc_init_array(void);
__libc_init_array();
fake_heap_start = &g_heap[0];
fake_heap_end = &g_heap[sizeof g_heap];
orig_ctx = ctx;
orig_main_thread = main_thread;
orig_saved_lr = saved_lr;
// Call constructors.
//void __libc_init_array(void);
__libc_init_array();
}
void __attribute__((weak)) NORETURN __libnx_exit(int rc)
{
// Call destructors.
//void __libc_fini_array(void);
__libc_fini_array();
void __attribute__((weak)) NORETURN __libnx_exit(int rc) {
// Call destructors.
//void __libc_fini_array(void);
__libc_fini_array();
SaltySD_printf("SaltySD Plugin: jumping to %p\n", orig_saved_lr);
SaltySD_printf("SaltySD Plugin: jumping to %p\n", orig_saved_lr);
__nx_exit(0, orig_saved_lr);
while (true);
__nx_exit(0, orig_saved_lr);
while (true);
}
int main(int argc, char *argv[])
{
SaltySD_printf("SaltySD Plugin: alive\n");
// Get anchor for imports
// do not remove if you plan on using IMPORT
ANCHOR_ABS = SaltySDCore_getCodeStart();
int main(int argc, char *argv[]) {
SaltySD_printf("SaltySD Plugin: alive\n");
// Get anchor for imports
// do not remove if you plan on using IMPORT
ANCHOR_ABS = SaltySDCore_getCodeStart();
/*
Example of string replacement:
replaces the title screen's version number with the string
below.
*/
/*
Example of string replacement:
replaces the title screen's version number with the string
below.
*/
const char *ver = "Ver. %d.%d.%d";
u64 version_string = SaltySDCore_findCode((u8 *)ver, strlen(ver));
if (version_string) {
SaltySD_Memcpy(version_string, (u64) "Salty v%d%d%d", 13);
}
const char *ver = "Ver. %d.%d.%d";
u64 version_string = SaltySDCore_findCode((u8 *)ver, strlen(ver));
if (version_string) {
SaltySD_Memcpy(version_string, (u64) "Salty v%d%d%d", 13);
}
// Necessary for script replacement
SaltySD_function_replace_sym("_ZN3lib8L2CAgent15clear_lua_stackEv", (u64) &clear_lua_stack_replace);
hitbox_vis_main();
training_mods_main();
// Necessary for script replacement
SaltySD_function_replace_sym("_ZN3lib8L2CAgent15clear_lua_stackEv", (u64) &clear_lua_stack_replace);
// Add function replacements here
hitbox_vis_main();
training_mods_main();
__libnx_exit(0);
__libnx_exit(0);
}

View file

@ -1,78 +1,82 @@
#ifndef NN_RO_H
#define NN_RO_H
#include <switch.h>
#define nn_ro_LoadModule _ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmi
extern uint64_t _ZN2nn2ro10LoadModuleEPNS0_6ModuleEPKvPvmi(void* module, void const* unk_1, void* unk_2, unsigned long unk_3, int unk_4) LINKABLE;
typedef unsigned char undefined;
typedef unsigned char byte;
typedef unsigned char dwfenc;
typedef unsigned int dword;
typedef long long longlong;
typedef unsigned long long qword;
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
typedef unsigned char undefined1;
typedef unsigned short undefined2;
typedef unsigned int undefined3;
typedef unsigned int undefined4;
typedef unsigned long long undefined5;
typedef unsigned long long undefined6;
typedef unsigned long long undefined7;
typedef unsigned long long undefined8;
typedef unsigned short ushort;
typedef unsigned short word;
typedef unsigned char undefined;
typedef unsigned char byte;
typedef unsigned char dwfenc;
typedef unsigned int dword;
typedef long long longlong;
typedef unsigned long long qword;
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ulonglong;
typedef unsigned char undefined1;
typedef unsigned short undefined2;
typedef unsigned int undefined3;
typedef unsigned int undefined4;
typedef unsigned long long undefined5;
typedef unsigned long long undefined6;
typedef unsigned long long undefined7;
typedef unsigned long long undefined8;
typedef unsigned short ushort;
typedef unsigned short word;
enum module_state {module_unloaded, module_loaded};
typedef struct RoModule_t {
struct RoModule_t *next;
struct RoModule_t *prev;
union {
void *rel;
void *rela;
void *raw;
} rela_or_rel_plt;
union {
void *rel;
void *rela;
} rela_or_rel;
uint64_t module_base;
void *dyanmic;
bool is_rela;
uint64_t rela_or_rel_plt_size;
void (*dt_init)(void);
void (*dt_fini)(void);
uint32_t *hash_bucket;
uint32_t *hash_chain;
char *dynstr;
void *dynsym;
uint64_t dynstr_size;
void **got;
uint64_t rela_dyn_size;
uint64_t rel_dyn_size;
uint64_t rel_count;
uint64_t rela_count;
uint64_t hash_nchain_value;
uint64_t hash_nbucket_value;
uint64_t got_stub_ptr;
struct RoModule_t *next;
struct RoModule_t *prev;
union {
void *rel;
void *rela;
void *raw;
} rela_or_rel_plt;
union {
void *rel;
void *rela;
} rela_or_rel;
uint64_t module_base;
void *dyanmic;
bool is_rela;
uint64_t rela_or_rel_plt_size;
void (*dt_init)(void);
void (*dt_fini)(void);
uint32_t *hash_bucket;
uint32_t *hash_chain;
char *dynstr;
void *dynsym;
uint64_t dynstr_size;
void **got;
uint64_t rela_dyn_size;
uint64_t rel_dyn_size;
uint64_t rel_count;
uint64_t rela_count;
uint64_t hash_nchain_value;
uint64_t hash_nbucket_value;
uint64_t got_stub_ptr;
} RoModule;
typedef struct Module_t {
RoModule *module;
enum module_state state;
uintptr_t module_address;
uintptr_t bss_address;
RoModule *module;
enum module_state state;
uintptr_t module_address;
uintptr_t bss_address;
} Module;
typedef struct SmashModule { /* PlaceHolder Structure */
Module module;
void * field_0x20;
void * src_buffer;
char name[256]; /* Created by retype action */
undefined field_0x130;
undefined field_0x131;
undefined4 is_loaded; // bool
Module module;
void *field_0x20;
void *src_buffer;
char name[256]; /* Created by retype action */
undefined field_0x130;
undefined field_0x131;
undefined4 is_loaded; // bool
} SmashModule;
# endif // NN_RO_H

View file

@ -23,21 +23,21 @@ using namespace app::lua_bind;
*/
const float segment_dict[15][5] = {
{0,RAYGUN_HEIGHT*2,0,0,0.25}, // a
{0,RAYGUN_HEIGHT,RAYGUN_LENGTH,90,0.25}, // b
{0,0,RAYGUN_LENGTH,90,0.25}, // c
{0,0,0,0,0.25}, // d
{0,0,0,90,0.25}, //e
{0,RAYGUN_HEIGHT,0,90,0.25}, // f
{0,RAYGUN_HEIGHT,0,0,0.25}, // g mid
{0,RAYGUN_HEIGHT,RAYGUN_LENGTH/2,90,0.25}, // h
{0,RAYGUN_HEIGHT,RAYGUN_LENGTH/2,52,0.2}, // i
{0,RAYGUN_HEIGHT,RAYGUN_LENGTH/2,-52,0.2}, //j
{0,0,RAYGUN_LENGTH/2,90,0.25}, // k
{0,RAYGUN_HEIGHT/2,RAYGUN_LENGTH*3/16,52,0.2}, // l
{0,RAYGUN_HEIGHT*3/2,RAYGUN_LENGTH*3/16,-52,0.2}, // m
{0,RAYGUN_HEIGHT,0,0,0.15}, // n
{0,RAYGUN_HEIGHT,RAYGUN_LENGTH/2,0,0.15}, // o
{0, RAYGUN_HEIGHT*2, 0, 0, 0.25}, // a
{0, RAYGUN_HEIGHT, RAYGUN_LENGTH, 90, 0.25}, // b
{0, 0, RAYGUN_LENGTH, 90, 0.25}, // c
{0, 0, 0, 0, 0.25}, // d
{0, 0, 0, 90, 0.25}, // e
{0, RAYGUN_HEIGHT, 0, 90, 0.25}, // f
{0, RAYGUN_HEIGHT, 0, 0, 0.25}, // g mid
{0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 90, 0.25}, // h
{0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 52, 0.2}, // i
{0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, -52, 0.2}, // j
{0, 0, RAYGUN_LENGTH/2, 90, 0.25}, // k
{0, RAYGUN_HEIGHT/2, RAYGUN_LENGTH*3/16, 52, 0.2}, // l
{0, RAYGUN_HEIGHT*3/2, RAYGUN_LENGTH*3/16, -52, 0.2}, // m
{0, RAYGUN_HEIGHT, 0, 0, 0.15}, // n
{0, RAYGUN_HEIGHT, RAYGUN_LENGTH/2, 0, 0.15}, // o
};
/*
@ -107,12 +107,12 @@ const char segment_rev[15] = {
};
void show_segment(u64 battle_object_module_accessor, float z, float y, float x, float zrot, float size) {
Hash40 raygunShot = {.hash = 0x11e470b07fLL};
Hash40 top = {.hash = 0x031ed91fcaLL};
Hash40 raygunShot = { .hash = 0x11e470b07fLL };
Hash40 top = { .hash = 0x031ed91fcaLL };
Vector3f pos = {.x = x, .y = y, .z = z};
Vector3f rot = {.x = 0, .y = 90, .z = zrot};
Vector3f random = {.x = 0, .y = 0, .z = 0};
Vector3f pos = { .x = x, .y = y, .z = z };
Vector3f rot = { .x = 0, .y = 90, .z = zrot };
Vector3f random = { .x = 0, .y = 0, .z = 0 };
EffectModule::req_on_joint(battle_object_module_accessor, raygunShot.hash, top.hash,
&pos, &rot, size,
@ -150,9 +150,9 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o
const float* segment;
int index = segment_str[i] - 'a';
if (facing_left == -1)
if (facing_left == -1) {
index = segment_rev[index] - 'a';
}
segment = segment_dict[index];
float z = segment[0];
@ -170,7 +170,7 @@ void print_char( u64 module_accessor, char to_print, int line_num, float horiz_o
void print_string( u64 module_accessor, const char* print_str) {
// Delete any previous strings
Hash40 raygunShot = {.hash = 0x11e470b07fLL};
Hash40 raygunShot = { .hash = 0x11e470b07fLL };
EffectModule::kill_kind(module_accessor, raygunShot.hash, 0, 1);
int line_num = 0;
@ -179,8 +179,9 @@ void print_string( u64 module_accessor, const char* print_str) {
float facing_left = PostureModule::lr(module_accessor);
if (strlen(print_str) <= 8 && strchr(print_str, '\n') == NULL)
if (strlen(print_str) <= 8 && strchr(print_str, '\n') == NULL) {
line_num = 1;
}
horiz_offset = 0;
char_num = 0;
for (size_t i = 0; i < strlen(print_str); i++) {
@ -196,10 +197,11 @@ void print_string( u64 module_accessor, const char* print_str) {
char_num++;
// short characters
if (curr_char == 'D' || curr_char == '1' )
if (curr_char == 'D' || curr_char == '1') {
horiz_offset += facing_left * (RAYGUN_LENGTH/2 + 3);
else
horiz_offset += facing_left * (RAYGUN_LENGTH+3);
} else {
horiz_offset += facing_left * (RAYGUN_LENGTH + 3);
}
if (char_num > 8) {
horiz_offset = 0;
@ -209,4 +211,4 @@ void print_string( u64 module_accessor, const char* print_str) {
}
}
#endif // RAYGUN_PRINTER_H
#endif // RAYGUN_PRINTER_H

View file

@ -6,9 +6,9 @@
#include "useful.h"
extern "C" {
u64 SaltySDCore_getCodeStart() LINKABLE;
u64 SaltySDCore_getCodeSize() LINKABLE;
u64 SaltySDCore_findCode(u8* code, size_t size) LINKABLE;
u64 SaltySDCore_getCodeStart() LINKABLE;
u64 SaltySDCore_getCodeSize() LINKABLE;
u64 SaltySDCore_findCode(u8* code, size_t size) LINKABLE;
}
#endif // SALTYSD_CORE_H

View file

@ -6,14 +6,14 @@
#include "useful.h"
extern "C" {
uint64_t SaltySDCore_GetSymbolAddr(void* base, char* name) LINKABLE;
uint64_t SaltySDCore_FindSymbol(char* name) LINKABLE;
uint64_t SaltySDCore_FindSymbolBuiltin(char* name) LINKABLE;
void SaltySDCore_RegisterModule(void* base) LINKABLE;
void SaltySDCore_RegisterBuiltinModule(void* base) LINKABLE;
void SaltySDCore_DynamicLinkModule(void* base) LINKABLE;
void SaltySDCore_ReplaceModuleImport(void* base, char* name, void* new_replace) LINKABLE;
void SaltySDCore_ReplaceImport(char* name, void* new_replace) LINKABLE;
uint64_t SaltySDCore_GetSymbolAddr(void* base, char* name) LINKABLE;
uint64_t SaltySDCore_FindSymbol(char* name) LINKABLE;
uint64_t SaltySDCore_FindSymbolBuiltin(char* name) LINKABLE;
void SaltySDCore_RegisterModule(void* base) LINKABLE;
void SaltySDCore_RegisterBuiltinModule(void* base) LINKABLE;
void SaltySDCore_DynamicLinkModule(void* base) LINKABLE;
void SaltySDCore_ReplaceModuleImport(void* base, char* name, void* new_replace) LINKABLE;
void SaltySDCore_ReplaceImport(char* name, void* new_replace) LINKABLE;
}
#endif // SALTYSD_DYNAMIC_H

36
source/saltysd_helper.cpp Normal file
View file

@ -0,0 +1,36 @@
#include <switch.h>
#include "saltysd_core.h"
#include "saltysd_ipc.h"
#include "saltysd_dynamic.h"
#include "nn_ro.h"
void (*SaltySD_installed_hook)(char*, u64) = NULL;
int SaltySD_function_replace(u64 addr, u64 new_func) {
if (addr) {
SaltySD_Memcpy(addr, (u64) "\x49\x00\x00\x58", 4); // LDR X9, .+8
SaltySD_Memcpy(addr+4, (u64) "\x20\x01\x1F\xD6", 4); // BR X9
SaltySD_Memcpy(addr+8, (u64) &new_func, 8); // .dword newaddr
return 0;
}
return -1;
}
int SaltySD_function_replace_sym(char* function_sym, u64 new_func) {
u64 addr = SaltySDCore_FindSymbol(function_sym);
return SaltySD_function_replace(addr, new_func);
}
void LoadModule(SmashModule *module, void *param_2, void *param_3, unsigned long param_4, int param_5) {
nn_ro_LoadModule(module, param_2, param_3, param_4, param_5);
if (SaltySD_installed_hook != NULL) {
SaltySD_installed_hook((char*)&module->name, (u64)module->module.module->module_base);
}
}
void SaltySD_install_nro_hook(u64 LoadModule_thunk_addr, void hook_main(char*, u64)) {
SaltySD_installed_hook = hook_main;
SaltySD_function_replace(LoadModule_thunk_addr, (u64) LoadModule);
}

View file

@ -2,43 +2,12 @@
#define SALTYSD_HELPER_H
#include <switch.h>
#include "saltysd_core.h"
#include "saltysd_ipc.h"
#include "saltysd_dynamic.h"
#include "nn_ro.h"
#define ANCHOR_REL 0x70ffffc000
u64 ANCHOR_ABS;
#define IMPORT(x) (x - ANCHOR_REL + ANCHOR_ABS)
void (*SaltySD_installed_hook)(char*, u64) = NULL;
int SaltySD_function_replace(u64 addr, u64 new_func) {
if (addr) {
SaltySD_Memcpy(addr, (u64) "\x49\x00\x00\x58", 4); // LDR X9, .+8
SaltySD_Memcpy(addr+4, (u64) "\x20\x01\x1F\xD6", 4); // BR X9
SaltySD_Memcpy(addr+8, (u64) &new_func, 8); // .dword newaddr
return 0;
}
return -1;
}
int SaltySD_function_replace_sym(char* function_sym, u64 new_func) {
u64 addr = SaltySDCore_FindSymbol(function_sym);
return SaltySD_function_replace(addr, new_func);
}
void LoadModule(SmashModule *module, void *param_2, void *param_3, unsigned long param_4, int param_5) {
nn_ro_LoadModule(module, param_2, param_3, param_4, param_5);
if(SaltySD_installed_hook != NULL) {
SaltySD_installed_hook((char*)&module->name, (u64)module->module.module->module_base);
}
}
void SaltySD_install_nro_hook(u64 LoadModule_thunk_addr, void hook_main(char*, u64)) {
SaltySD_installed_hook = hook_main;
SaltySD_function_replace(LoadModule_thunk_addr, (u64) LoadModule);
}
int SaltySD_function_replace(u64 addr, u64 new_func);
int SaltySD_function_replace_sym(char* function_sym, u64 new_func);
#endif // SALTYSD_HELPER_H

View file

@ -6,14 +6,14 @@
#include "useful.h"
extern "C" {
void SaltySD_Init() LINKABLE;
Result SaltySD_Deinit() LINKABLE;
Result SaltySD_Term() LINKABLE;
Result SaltySD_Restore() LINKABLE;
Result SaltySD_LoadELF(u64 heap, u64* elf_addr, u64* elf_size, char* name) LINKABLE;
Result SaltySD_Memcpy(u64 to, u64 from, u64 size) LINKABLE;
Result SaltySD_GetSDCard(Handle *retrieve) LINKABLE;
Result SaltySD_printf(const char* format, ...) LINKABLE;
void SaltySD_Init() LINKABLE;
Result SaltySD_Deinit() LINKABLE;
Result SaltySD_Term() LINKABLE;
Result SaltySD_Restore() LINKABLE;
Result SaltySD_LoadELF(u64 heap, u64* elf_addr, u64* elf_size, char* name) LINKABLE;
Result SaltySD_Memcpy(u64 to, u64 from, u64 size) LINKABLE;
Result SaltySD_GetSDCard(Handle *retrieve) LINKABLE;
Result SaltySD_printf(const char* format, ...) LINKABLE;
}
#endif //SALTYSD_IPC_H

View file

@ -3,11 +3,10 @@
#include <stdint.h>
#include "crc32.h"
#include "useful.h"
#include "l2c.hpp"
#include "l2c_imports.hpp"
#include "acmd_wrapper.hpp"
#include "lua_helper.hpp"
#include "raygun_printer.hpp"
@ -36,99 +35,84 @@ void replace_scripts(L2CAgent* l2c_agent, u8 category, int kind) {
}
u64 appeal_lw_replace(L2CAgent* l2c_agent, void* variadic) {
ACMD acmd = ACMD(l2c_agent);
ACMD acmd = ACMD(l2c_agent);
acmd.frame(1);
if (acmd.is_excute()) {
TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES;
if (TOGGLE_STATE == MASH_AIRDODGE)
print_string(acmd.module_accessor, "MASH\nAIRDODGE");
else if (TOGGLE_STATE == MASH_JUMP)
print_string(acmd.module_accessor, "MASH\nJUMP");
else
print_string(acmd.module_accessor, "NONE");
}
acmd.frame(1);
if (acmd.is_excute()) {
TOGGLE_STATE = (TOGGLE_STATE + 1) % NUM_TOGGLE_STATES;
if (TOGGLE_STATE == MASH_AIRDODGE)
print_string(acmd.module_accessor, "MASH\nAIRDODGE");
else if (TOGGLE_STATE == MASH_JUMP)
print_string(acmd.module_accessor, "MASH\nJUMP");
else
print_string(acmd.module_accessor, "NONE");
}
return 0;
return 0;
}
u64 appeal_hi_replace(L2CAgent* l2c_agent, void* variadic) {
ACMD acmd = ACMD(l2c_agent);
ACMD acmd = ACMD(l2c_agent);
acmd.frame(1);
if (acmd.is_excute()) {
HITBOX_VIS = !HITBOX_VIS;
if (HITBOX_VIS)
print_string(acmd.module_accessor, "HITBOX\nVIS");
else
print_string(acmd.module_accessor, "NO\nHITBOX");
}
acmd.frame(1);
if (acmd.is_excute()) {
HITBOX_VIS = !HITBOX_VIS;
if (HITBOX_VIS)
print_string(acmd.module_accessor, "HITBOX\nVIS");
else
print_string(acmd.module_accessor, "NO\nHITBOX");
}
return 0;
return 0;
}
u64 appeal_s_replace(L2CAgent* l2c_agent, void* variadic) {
ACMD acmd = ACMD(l2c_agent);
ACMD acmd = ACMD(l2c_agent);
acmd.frame(1);
if (acmd.is_excute()) {
DI_STATE = (DI_STATE + 1) % NUM_DI_STATES;
const char* DI_strings[NUM_DI_STATES] = {"NONE", "AWAY", "DOWN AWAY", "DOWN", "DOWN IN",
"IN", "UP IN", "UP", "UP AWAY", "RANDOM\nIN AWAY"};
print_string(acmd.module_accessor, DI_strings[DI_STATE]);
}
acmd.frame(1);
if (acmd.is_excute()) {
DI_STATE = (DI_STATE + 1) % NUM_DI_STATES;
const char* DI_strings[NUM_DI_STATES] = {"NONE", "AWAY", "DOWN AWAY", "DOWN", "DOWN IN",
"IN", "UP IN", "UP", "UP AWAY", "RANDOM\nIN AWAY"};
print_string(acmd.module_accessor, DI_strings[DI_STATE]);
}
return 0;
}
// AnimCMD replacement function
u64 shine_replace(L2CAgent* l2c_agent, void* variadic) {
ACMD acmd = ACMD(l2c_agent);
acmd.frame(1);
if (acmd.is_excute()) {
acmd.ATTACK(0, 0, hash40("top"), 10.0, 10, 32, 0, 66, 7.5, 0, 6.5,
// 0, 0, 0, //L2C_voids: no X2, Y2, Z2
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 63, 31, 0,
0x13462FCFE4LL, 2, 7, 25);
}
return 0;
return 0;
}
void* sv_get_status_func(u64 l2c_agentbase, int status_kind, u64 key) {
u64 unk48 = LOAD64(l2c_agentbase + 0x48);
u64 unk50 = LOAD64(l2c_agentbase + 0x50);
if ( 0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind)
return *(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29));
return 0;
u64 unk48 = LOAD64(l2c_agentbase + 0x48);
u64 unk50 = LOAD64(l2c_agentbase + 0x50);
if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind)
return *(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29));
return 0;
}
void sv_replace_status_func(u64 l2c_agentbase, int status_kind, u64 key, void* func) {
u64 unk48 = LOAD64(l2c_agentbase + 0x48);
u64 unk50 = LOAD64(l2c_agentbase + 0x50);
if ( 0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) {
*(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)) = func;
}
u64 unk48 = LOAD64(l2c_agentbase + 0x48);
u64 unk50 = LOAD64(l2c_agentbase + 0x50);
if (0x2E8BA2E8BA2E8BA3LL * ((unk50 - unk48) >> 4) > (u64)status_kind) {
*(void **)(unk48 + 0xB0LL * status_kind + (key << 32 >> 29)) = func;
}
}
u64 clear_lua_stack_replace(u64 l2c_agent) {
u64 lua_state = LOAD64(l2c_agent + 8);
if (lua_state-8 && LOAD64(lua_state-8) && LOAD64(LOAD64(lua_state - 8) + 416LL)) {
u8 battle_object_category = *(u8 *)(LOAD64(lua_state - 8) + 404LL);
int battle_object_kind = *(int *)(LOAD64(lua_state - 8) + 408LL);
replace_scripts((L2CAgent*)l2c_agent, battle_object_category, battle_object_kind);
}
u64 lua_state = LOAD64(l2c_agent + 8);
if ((lua_state - 8) && LOAD64(lua_state - 8) && (LOAD64(LOAD64(lua_state - 8) + 416LL))) {
u8 battle_object_category = *(u8 *)(LOAD64(lua_state - 8) + 404LL);
int battle_object_kind = *(int *)(LOAD64(lua_state - 8) + 408LL);
replace_scripts((L2CAgent*)l2c_agent, battle_object_category, battle_object_kind);
}
// Original clear_lua_stack:
u64 v1 = LOAD64(l2c_agent + 8);
u64 v2 = LOAD64(v1 + 16);
u64 i = LOAD64(LOAD64(v1 + 32)) + 16LL;
for (; v2 < i; v2 = LOAD64(v1 + 16)) {
LOAD64(v1 + 16) = v2 + 16;
*(u32 *)(v2 + 8) = 0;
}
LOAD64(v1 + 16) = i;
return l2c_agent;
// Original clear_lua_stack:
u64 v1 = LOAD64(l2c_agent + 8);
u64 v2 = LOAD64(v1 + 16);
u64 i = LOAD64(LOAD64(v1 + 32)) + 16LL;
for (; v2 < i; v2 = LOAD64(v1 + 16)) {
LOAD64(v1 + 16) = v2 + 16;
*(u32 *)(v2 + 8) = 0;
}
LOAD64(v1 + 16) = i;
return l2c_agent;
}

View file

@ -21,4 +21,4 @@ int DI_STATE = 0;
int TOGGLE_STATE = 0;
#define NUM_TOGGLE_STATES 3
#endif // TAUNT_TOGGLES_H
#endif // TAUNT_TOGGLES_H

View file

@ -1,6 +1,6 @@
#include "l2c.hpp"
#include "saltysd_helper.hpp"
#include "useful.h"
#include "l2c_imports.hpp"
#include "saltysd_helper.hpp"
#include "acmd_imports.hpp"
#include "taunt_toggles.h"
#include "raygun_printer.hpp"
@ -12,130 +12,122 @@ using namespace app::sv_animcmd;
u64 fighter_manager_addr;
bool is_operation_cpu(u64 module_accessor) {
int entry_id = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
u64 fighter_information = FighterManager::get_fighter_information(LOAD64(fighter_manager_addr), entry_id);
int entry_id = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_ENTRY_ID);
u64 fighter_information = FighterManager::get_fighter_information(LOAD64(fighter_manager_addr), entry_id);
return FighterInformation::is_operation_cpu(fighter_information);
return FighterInformation::is_operation_cpu(fighter_information);
}
bool is_in_hitstun(u64 module_accessor) {
int status_kind = StatusModule::status_kind(module_accessor);
return status_kind >= FIGHTER_STATUS_KIND_DAMAGE && status_kind <= FIGHTER_STATUS_KIND_DAMAGE_FALL;
int status_kind = StatusModule::status_kind(module_accessor);
return status_kind >= FIGHTER_STATUS_KIND_DAMAGE && status_kind <= FIGHTER_STATUS_KIND_DAMAGE_FALL;
}
void perform_jump(u64 module_accessor) {
int jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
int max_jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT_MAX);
if (jump_count < max_jump_count) {
if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_AIR) {
if (WorkModule::get_param_int(module_accessor, 0xB99CC3FBCLL, 0) == FIGHTER_JUMP_AERIAL_TYPE_NORMAL)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_AERIAL, 1);
else
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_FLY, 1);
} else if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_GROUND)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_SQUAT, 1);
WorkModule::inc_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
}
int jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
int max_jump_count = WorkModule::get_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT_MAX);
if (jump_count < max_jump_count) {
if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_AIR) {
if (WorkModule::get_param_int(module_accessor, 0xB99CC3FBCLL, 0) == FIGHTER_JUMP_AERIAL_TYPE_NORMAL)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_AERIAL, 1);
else
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_FLY, 1);
} else if (StatusModule::situation_kind(module_accessor) == SITUATION_KIND_GROUND) {
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_JUMP_SQUAT, 1);
}
WorkModule::inc_int(module_accessor, FIGHTER_INSTANCE_WORK_ID_INT_JUMP_COUNT);
}
}
namespace app::lua_bind::WorkModule {
// Force option out of hitstun
u64 enable_transition_term_group_replace(u64 module_accessor, int transition_group) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
if (is_in_hitstun(module_accessor)) {
// Airdodge
if (TOGGLE_STATE == MASH_AIRDODGE) {
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_ESCAPE)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
}
// Jump
else if (TOGGLE_STATE == MASH_JUMP) {
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_JUMP_AERIAL)
perform_jump(module_accessor);
else if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_GROUND_JUMP)
perform_jump(module_accessor);
}
}
}
// Force option out of hitstun
u64 enable_transition_term_group_replace(u64 module_accessor, int transition_group) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
if (is_in_hitstun(module_accessor)) {
if (TOGGLE_STATE == MASH_AIRDODGE) { // airdodge
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_ESCAPE)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
} else if (TOGGLE_STATE == MASH_JUMP) { // jump
if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_AIR_JUMP_AERIAL)
perform_jump(module_accessor);
else if (transition_group == FIGHTER_STATUS_TRANSITION_GROUP_CHK_GROUND_JUMP)
perform_jump(module_accessor);
}
}
}
// call original WorkModule::enable_transition_term_group_impl
u64 work_module = load_module(module_accessor, 0x50);
u64 (*enable_transition_term_group)(u64, u64) = (u64(*)(u64, u64))(load_module_impl(work_module, 0x140));
// call original WorkModule::enable_transition_term_group_impl
u64 work_module = load_module(module_accessor, 0x50);
u64 (*enable_transition_term_group)(u64, u64) = (u64(*)(u64, u64))(load_module_impl(work_module, 0x140));
return enable_transition_term_group(work_module, transition_group);
}
return enable_transition_term_group(work_module, transition_group);
}
// Force DI
float get_float_replace(u64 module_accessor, int var) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
if (is_in_hitstun(module_accessor)) {
if (DI_STATE != NONE) {
float angle = (DI_STATE - 1) * M_PI / 4.0;
// Force DI
float get_float_replace(u64 module_accessor, int var) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
if (is_in_hitstun(module_accessor)) {
if (DI_STATE != NONE) {
float angle = (DI_STATE - 1) * M_PI / 4.0;
// Either 0 (right) or PI (left)
if (DI_STATE == DI_RANDOM_IN_AWAY) {
angle = app::sv_math::rand(hash40("fighter"), 2) * M_PI;
}
// Either 0 (right) or PI (left)
if (DI_STATE == DI_RANDOM_IN_AWAY) {
angle = app::sv_math::rand(hash40("fighter"), 2) * M_PI;
}
// If facing left, reverse angle
if (PostureModule::lr(module_accessor) != -1.0)
angle -= M_PI;
// If facing left, reverse angle
if (PostureModule::lr(module_accessor) != -1.0)
angle -= M_PI;
if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X)
return cos(angle);
if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_X)
return cos(angle);
if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y)
return sin(angle);
}
}
}
if (var == FIGHTER_STATUS_DAMAGE_WORK_FLOAT_VECOR_CORRECT_STICK_Y)
return sin(angle);
}
}
}
// call original WorkModule::get_float_impl
u64 work_module = load_module(module_accessor, 0x50);
float (*get_float)(u64, int) = (float (*)(u64, int))(load_module_impl(work_module, 0x58));
// call original WorkModule::get_float_impl
u64 work_module = load_module(module_accessor, 0x50);
float (*get_float)(u64, int) = (float (*)(u64, int))(load_module_impl(work_module, 0x58));
return get_float(work_module, var);
}
return get_float(work_module, var);
}
}
namespace app::lua_bind::MotionModule {
void change_motion_replace(u64 module_accessor, u64 motion_kind, float start_frame, float frame_speed_mult, bool unk1, float unk2, bool unk3, bool unk4) {
u64 curr_motion_kind = MotionModule::motion_kind(module_accessor);
if ((curr_motion_kind == hash40("damage_air_1") ||
curr_motion_kind == hash40("damage_air_2") ||
curr_motion_kind == hash40("damage_air_3")) && motion_kind == hash40("fall")) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
// Airdodge
if (TOGGLE_STATE == MASH_AIRDODGE)
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
// Jump
else if (TOGGLE_STATE == MASH_JUMP)
perform_jump(module_accessor);
}
}
void change_motion_replace(u64 module_accessor, u64 motion_kind, float start_frame, float frame_speed_mult, bool unk1, float unk2, bool unk3, bool unk4) {
u64 curr_motion_kind = MotionModule::motion_kind(module_accessor);
if ((curr_motion_kind == hash40("damage_air_1") ||
curr_motion_kind == hash40("damage_air_2") ||
curr_motion_kind == hash40("damage_air_3")) && motion_kind == hash40("fall")) {
if (is_training_mode() && is_operation_cpu(module_accessor)) {
if (TOGGLE_STATE == MASH_AIRDODGE) // airdodge
StatusModule::change_status_request_from_script(module_accessor, FIGHTER_STATUS_KIND_ESCAPE_AIR, 1);
else if (TOGGLE_STATE == MASH_JUMP) // jump
perform_jump(module_accessor);
}
}
// call original
u64 motion_module = load_module(module_accessor, 0x88);
void (*change_motion)(u64, u64, float, float, bool, float, bool, bool) =
(void (*)(u64, u64, float, float, bool, float, bool, bool)) load_module_impl(motion_module, 0xD8);
// call original
u64 motion_module = load_module(module_accessor, 0x88);
void (*change_motion)(u64, u64, float, float, bool, float, bool, bool) =
(void (*)(u64, u64, float, float, bool, float, bool, bool)) load_module_impl(motion_module, 0xD8);
change_motion(motion_module, motion_kind, start_frame, frame_speed_mult, unk1, unk2, unk3, unk4);
}
change_motion(motion_module, motion_kind, start_frame, frame_speed_mult, unk1, unk2, unk3, unk4);
}
}
void training_mods_main() {
fighter_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E");
SaltySD_function_replace_sym(
"_ZN3app8lua_bind45WorkModule__enable_transition_term_group_implEPNS_26BattleObjectModuleAccessorEi",
(u64)&WorkModule::enable_transition_term_group_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi",
(u64)&WorkModule::get_float_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind32MotionModule__change_motion_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Effbfbb",
(u64)&MotionModule::change_motion_replace);
}
fighter_manager_addr = SaltySDCore_FindSymbol("_ZN3lib9SingletonIN3app14FighterManagerEE9instance_E");
SaltySD_function_replace_sym(
"_ZN3app8lua_bind45WorkModule__enable_transition_term_group_implEPNS_26BattleObjectModuleAccessorEi",
(u64)&WorkModule::enable_transition_term_group_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind26WorkModule__get_float_implEPNS_26BattleObjectModuleAccessorEi",
(u64)&WorkModule::get_float_replace);
SaltySD_function_replace_sym(
"_ZN3app8lua_bind32MotionModule__change_motion_implEPNS_26BattleObjectModuleAccessorEN3phx6Hash40Effbfbb",
(u64)&MotionModule::change_motion_replace);
}

View file

@ -7,8 +7,20 @@
#define LINKABLE __attribute__ ((weak))
#define debug_log(...) \
{char log_buf[0x200]; snprintf(log_buf, 0x200, __VA_ARGS__); \
svcOutputDebugString(log_buf, strlen(log_buf));}
#define LOAD64 *(u64 *)
#define debug_log(...) {\
char log_buf[0x200]; snprintf(log_buf, 0x200, __VA_ARGS__); \
svcOutputDebugString(log_buf, strlen(log_buf)); }
typedef struct Hash40 {
uint64_t hash : 40;
} Hash40;
typedef struct Vector3f {
float x;
float y;
float z;
} Vector3f;
#endif // USEFUL_H

35
source/useful_visual.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "useful_visual.h"
#include <math.h>
#include "useful.h"
float round_to(float val, float align) {
return roundf(val / align) * align;
}
float lerp(float min, float max, float t) {
return min + (max - min) * t;
}
float unlerp(float min, float max, float val) {
return (val - min) / (max - min);
}
float lerp_bounded(float min, float max, float t) {
return t <= 0 ? min : t >= 1 ? max : lerp(min, max, t);
}
float unlerp_bounded(float min, float max, float val) {
return val <= min ? 0 : val >= max ? 1 : unlerp(min, max, val);
}
Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, float gamma) {
float gamma_inv = 1.0f / gamma;
float align = 1.0f / 255.0f; // color components must be a multiple of 1/255
return {
round_to(powf(lerp_bounded(powf(min_color.x, gamma), powf(max_color.x, gamma), t), gamma_inv), align),
round_to(powf(lerp_bounded(powf(min_color.y, gamma), powf(max_color.y, gamma), t), gamma_inv), align),
round_to(powf(lerp_bounded(powf(min_color.z, gamma), powf(max_color.z, gamma), t), gamma_inv), align)
};
}

31
source/useful_visual.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef USEFUL_VISUAL_H
#define USEFUL_VISUAL_H
#include "useful.h"
/**
* Rounds a number to the nearest multiple of another number.
*/
float round_to(float val, float align);
/**
* Linearly interpolates between two numbers, without bounds checking.
*/
float lerp(float min, float max, float t);
float unlerp(float min, float max, float val);
/**
* Linearly interpolates between two numbers, with bounds checking.
*/
float lerp_bounded(float min, float max, float t);
float unlerp_bounded(float min, float max, float 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
*/
Vector3f color_lerp(Vector3f min_color, Vector3f max_color, float t, float gamma = 2.0f);
#endif // USEFUL_VISUAL_H