mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2025-04-26 15:39:17 +00:00
* Apply Bit Flag Defensive Options * Apply Bit Flag Followups * Apply Bit Flag Mash options * Update Version String
551 lines
No EOL
17 KiB
C++
551 lines
No EOL
17 KiB
C++
#include <tesla.hpp>
|
|
#include "gui_main.hpp"
|
|
#include "gui_help.hpp"
|
|
#include "value_list_item.hpp"
|
|
#include "clickable_list_item.hpp"
|
|
#include "taunt_toggles.hpp"
|
|
|
|
static struct TrainingModpackMenu
|
|
{
|
|
int HITBOX_VIS = true;
|
|
int DI_STATE = NONE;
|
|
int LEFT_STICK = NONE;
|
|
ActionFlags MASH_STATE = ActionFlags::None;
|
|
ActionFlags FOLLOW_UP = ActionFlags::None;
|
|
LedgeFlags LEDGE_STATE = LedgeFlags::All;
|
|
TechFlags TECH_STATE = TechFlags::All;
|
|
int SHIELD_STATE = NONE;
|
|
DefensiveFlags DEFENSIVE_STATE = DefensiveFlags::All;
|
|
int OOS_OFFSET = 0;
|
|
int REACTION_TIME = 0;
|
|
int MASH_IN_NEUTRAL = false;
|
|
int FAST_FALL = false;
|
|
int FAST_FALL_DELAY = 0;
|
|
int FALLING_AERIALS = false;
|
|
int FULL_HOP = false;
|
|
} menu;
|
|
|
|
static int FRAME_ADVANTAGE = 0;
|
|
|
|
u64 pidSmash = 0;
|
|
static const char* SYSTEM_SETTINGS_FILE = "/atmosphere/config/system_settings.ini";
|
|
static const char* TRAINING_MOD_LOG = "/TrainingModpack/training_modpack.log";
|
|
static const char* TRAINING_MOD_FRAME_ADV_LOG = "/TrainingModpack/training_modpack_frame_adv.log";
|
|
static const char* TRAINING_MOD_CONF = "/TrainingModpack/training_modpack_menu.conf";
|
|
|
|
static tsl::hlp::ini::IniData readSettings()
|
|
{
|
|
/* Open Sd card filesystem. */
|
|
FsFileSystem fsSdmc;
|
|
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return {};
|
|
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
|
|
|
|
/* Open config file. */
|
|
FsFile fileConfig;
|
|
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Read, &fileConfig))) return {};
|
|
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
|
|
|
|
/* Get config file size. */
|
|
s64 configFileSize;
|
|
if(R_FAILED(fsFileGetSize(&fileConfig, &configFileSize))) return {};
|
|
|
|
/* Read and parse config file. */
|
|
std::string configFileData(configFileSize, '\0');
|
|
u64 readSize;
|
|
Result rc = fsFileRead(&fileConfig, 0, configFileData.data(), configFileSize, FsReadOption_None, &readSize);
|
|
if(R_FAILED(rc) || readSize != static_cast<u64>(configFileSize)) return {};
|
|
|
|
return tsl::hlp::ini::parseIni(configFileData);
|
|
}
|
|
|
|
static void writeSettings(tsl::hlp::ini::IniData const& iniData)
|
|
{
|
|
/* Open Sd card filesystem. */
|
|
FsFileSystem fsSdmc;
|
|
if(R_FAILED(fsOpenSdCardFileSystem(&fsSdmc))) return;
|
|
tsl::hlp::ScopeGuard fsGuard([&] { fsFsClose(&fsSdmc); });
|
|
|
|
std::string iniString = tsl::hlp::ini::unparseIni(iniData);
|
|
|
|
fsFsDeleteFile(&fsSdmc, SYSTEM_SETTINGS_FILE);
|
|
fsFsCreateFile(&fsSdmc, SYSTEM_SETTINGS_FILE, iniString.length(), 0);
|
|
|
|
/* Open config file. */
|
|
FsFile fileConfig;
|
|
if(R_FAILED(fsFsOpenFile(&fsSdmc, SYSTEM_SETTINGS_FILE, FsOpenMode_Write, &fileConfig))) return;
|
|
tsl::hlp::ScopeGuard fileGuard([&] { fsFileClose(&fileConfig); });
|
|
|
|
fsFileWrite(&fileConfig, 0, iniString.c_str(), iniString.length(), FsWriteOption_Flush);
|
|
}
|
|
|
|
static void updateSettings(tsl::hlp::ini::IniData const& changes)
|
|
{
|
|
tsl::hlp::ini::IniData iniData = readSettings();
|
|
for(auto& section : changes)
|
|
{
|
|
for(auto& keyValue : section.second)
|
|
{
|
|
iniData[section.first][keyValue.first] = keyValue.second;
|
|
}
|
|
}
|
|
writeSettings(iniData);
|
|
}
|
|
|
|
GuiMain::GuiMain()
|
|
{
|
|
smInitialize();
|
|
pminfoInitialize();
|
|
pmbmInitialize();
|
|
smExit();
|
|
|
|
pmdmntGetProcessId(&pidSmash, 0x01006A800016E000);
|
|
|
|
Result rc = fsOpenSdCardFileSystem(&this->m_fs);
|
|
if(R_FAILED(rc)) return;
|
|
|
|
FsFile menuFile;
|
|
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_CONF, FsOpenMode_Read, &menuFile);
|
|
if(R_FAILED(rc)) return;
|
|
|
|
u64 bytesRead;
|
|
rc = fsFileRead(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsReadOption_None, &bytesRead);
|
|
if(R_FAILED(rc))
|
|
{
|
|
fsFileWrite(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsOpenMode_Write);
|
|
}
|
|
|
|
fsFileClose(&menuFile);
|
|
}
|
|
|
|
GuiMain::~GuiMain()
|
|
{
|
|
smInitialize();
|
|
pminfoExit();
|
|
pmbmExit();
|
|
smExit();
|
|
}
|
|
|
|
static char FrameAdvantage[672];
|
|
|
|
class FrameAdvantageOverlayFrame : public tsl::elm::OverlayFrame
|
|
{
|
|
public:
|
|
FrameAdvantageOverlayFrame(const std::string& title, const std::string& subtitle) : tsl::elm::OverlayFrame(title, subtitle)
|
|
{}
|
|
|
|
virtual void draw(tsl::gfx::Renderer* renderer) override
|
|
{
|
|
renderer->clearScreen();
|
|
|
|
renderer->drawRect(0, 0, tsl::cfg::FramebufferWidth, 85, a(tsl::style::color::ColorFrameBackground));
|
|
|
|
renderer->drawString(this->m_title.c_str(), false, 20, 50, 30, a(tsl::style::color::ColorText));
|
|
renderer->drawString(this->m_subtitle.c_str(), false, 20, 70, 15, a(tsl::style::color::ColorDescription));
|
|
|
|
if(this->m_contentElement != nullptr) this->m_contentElement->frame(renderer);
|
|
}
|
|
};
|
|
|
|
class GuiFrameAdvantage : public tsl::Gui
|
|
{
|
|
public:
|
|
GuiFrameAdvantage()
|
|
{
|
|
tsl::hlp::requestForeground(false);
|
|
smInitialize();
|
|
pminfoInitialize();
|
|
pmbmInitialize();
|
|
smExit();
|
|
|
|
pmdmntGetProcessId(&pidSmash, 0x01006A800016E000);
|
|
|
|
Result rc = fsOpenSdCardFileSystem(&this->m_fs);
|
|
if(R_FAILED(rc)) return;
|
|
}
|
|
|
|
~GuiFrameAdvantage()
|
|
{
|
|
smInitialize();
|
|
pminfoExit();
|
|
pmbmExit();
|
|
smExit();
|
|
}
|
|
|
|
virtual tsl::elm::Element* createUI() override
|
|
{
|
|
snprintf(FrameAdvantage, 256, "Frame Advantage: %d", FRAME_ADVANTAGE);
|
|
auto rootFrame = new FrameAdvantageOverlayFrame(FrameAdvantage, "\uE0A2 + \uE07B Back");
|
|
|
|
this->rootFrame = rootFrame;
|
|
|
|
return rootFrame;
|
|
}
|
|
|
|
virtual void update() override
|
|
{
|
|
static u32 counter = 0;
|
|
|
|
if(counter++ % 10 != 0) return;
|
|
|
|
Result rc;
|
|
Handle debug;
|
|
|
|
if(pidSmash != 0)
|
|
{
|
|
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
if(R_SUCCEEDED(rc))
|
|
{
|
|
u64 frame_adv_addr = 0;
|
|
FsFile menuAddrFile;
|
|
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_FRAME_ADV_LOG, FsOpenMode_Read, &menuAddrFile);
|
|
if(R_FAILED(rc))
|
|
{
|
|
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Failed to open file with error %d", rc);
|
|
rootFrame->setTitle(FrameAdvantage);
|
|
svcCloseHandle(debug);
|
|
return;
|
|
}
|
|
|
|
char buffer[100];
|
|
u64 bytesRead;
|
|
rc = fsFileRead(&menuAddrFile, 0, buffer, 100, FsReadOption_None, &bytesRead);
|
|
if(R_FAILED(rc))
|
|
{
|
|
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Failed to read file with error %d", rc);
|
|
rootFrame->setTitle(FrameAdvantage);
|
|
svcCloseHandle(debug);
|
|
return;
|
|
}
|
|
|
|
fsFileClose(&menuAddrFile);
|
|
buffer[bytesRead] = '\0';
|
|
frame_adv_addr = strtoul(buffer, NULL, 16);
|
|
|
|
if(frame_adv_addr != 0)
|
|
{
|
|
rc = svcReadDebugProcessMemory(&FRAME_ADVANTAGE, debug, frame_adv_addr, sizeof(int));
|
|
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Frame Advantage: %d", FRAME_ADVANTAGE);
|
|
rootFrame->setTitle(FrameAdvantage);
|
|
}
|
|
|
|
svcCloseHandle(debug);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snprintf(FrameAdvantage, sizeof FrameAdvantage, "Smash is not running.");
|
|
rootFrame->setTitle(FrameAdvantage);
|
|
}
|
|
}
|
|
virtual bool handleInput(u64 keysDown,
|
|
u64 keysHeld,
|
|
touchPosition touchInput,
|
|
JoystickPosition leftJoyStick,
|
|
JoystickPosition rightJoyStick) override
|
|
{
|
|
if(keysHeld & KEY_DLEFT)
|
|
{
|
|
if(keysHeld & KEY_X)
|
|
{
|
|
tsl::goBack();
|
|
tsl::hlp::requestForeground(true);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// intercept B inputs
|
|
if(keysDown & KEY_B)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FrameAdvantageOverlayFrame* rootFrame;
|
|
FsFileSystem m_fs;
|
|
};
|
|
|
|
namespace
|
|
{
|
|
template<typename T> tsl::elm::ListItem* createBitFlagOption(T* option, const std::string& name, const std::string& help)
|
|
{
|
|
using FlagType = typename T::Type;
|
|
|
|
auto item = new tsl::elm::ListItem(name);
|
|
item->setClickListener([name, help, option](u64 keys) -> bool {
|
|
if(keys & KEY_A)
|
|
{
|
|
tsl::changeTo<GuiLambda>([option, name]() -> tsl::elm::Element* {
|
|
auto toggleList = new tsl::elm::List();
|
|
std::vector<tsl::elm::ToggleListItem*> items;
|
|
for(auto& [flag, str] : detail::EnumArray<FlagType>::values)
|
|
{
|
|
items.emplace_back(new BitFlagToggleListItem<FlagType>(str, flag, option));
|
|
}
|
|
|
|
auto allOff = new SetToggleListItem({}, items, "None");
|
|
auto allOn = new SetToggleListItem(items, {}, "All");
|
|
|
|
toggleList->addItem(allOn);
|
|
toggleList->addItem(allOff);
|
|
|
|
for(auto it : items)
|
|
{
|
|
toggleList->addItem(it);
|
|
}
|
|
|
|
auto frame = new tsl::elm::OverlayFrame(name, "");
|
|
frame->setContent(toggleList);
|
|
return frame;
|
|
});
|
|
return true;
|
|
}
|
|
if(keys & KEY_Y)
|
|
{
|
|
tsl::changeTo<GuiHelp>(name, help);
|
|
}
|
|
return false;
|
|
});
|
|
return item;
|
|
}
|
|
} // namespace
|
|
|
|
tsl::elm::Element* GuiMain::createUI()
|
|
{
|
|
char buffer[256];
|
|
snprintf(buffer, 256, "Version %s", VERSION);
|
|
tsl::elm::OverlayFrame* rootFrame = new tsl::elm::OverlayFrame("Training Modpack", buffer);
|
|
|
|
auto list = new tsl::elm::List();
|
|
|
|
Result rc;
|
|
Handle debug;
|
|
|
|
tsl::hlp::ini::IniData iniData = readSettings();
|
|
bool ease_nro_restriction = false;
|
|
for(auto& section : iniData)
|
|
{
|
|
for(auto& keyValue : section.second)
|
|
{
|
|
if(section.first == "ro")
|
|
{
|
|
if(keyValue.first == "ease_nro_restriction")
|
|
{
|
|
ease_nro_restriction = (readSettings()["ro"]["ease_nro_restriction"] == "u8!0x1");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!ease_nro_restriction)
|
|
{
|
|
tsl::elm::Element* iniShow = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
renderer->drawString(
|
|
"Your config file did not have the \nproper configuration to run the \nTraining Modpack.\n\n\nIt has been automatically \nupdated.\n- atmosphere\n---- config\n-------- system_settings.ini\n\n(enable ease_nro_restriction)\n\n\nPlease reboot your Switch.",
|
|
false,
|
|
50,
|
|
225,
|
|
20,
|
|
tsl::Color(255, 255, 255, 255));
|
|
});
|
|
|
|
updateSettings({{"ro", {{"ease_nro_restriction", "u8!0x1"}}}});
|
|
|
|
rootFrame->setContent(iniShow);
|
|
return rootFrame;
|
|
}
|
|
|
|
if(pidSmash != 0)
|
|
{
|
|
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
if(R_SUCCEEDED(rc))
|
|
{
|
|
svcCloseHandle(debug);
|
|
|
|
ClickableListItem* frameAdvantageItem = new ClickableListItem("Frame Advantage",
|
|
frame_advantage_items,
|
|
nullptr,
|
|
"frameAdvantage",
|
|
0,
|
|
"Frame Advantage",
|
|
frame_advantage_help);
|
|
frameAdvantageItem->setClickListener([](std::vector<std::string> values,
|
|
int* curValue,
|
|
std::string extdata,
|
|
int index,
|
|
std::string title,
|
|
std::string help) { tsl::changeTo<GuiFrameAdvantage>(); });
|
|
frameAdvantageItem->setHelpListener(
|
|
[](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
list->addItem(frameAdvantageItem);
|
|
|
|
ValueListItem* hitboxItem =
|
|
new ValueListItem("Hitbox Visualization", on_off, &menu.HITBOX_VIS, "hitbox", hitbox_help);
|
|
list->addItem(hitboxItem);
|
|
valueListItems.push_back(hitboxItem);
|
|
|
|
ValueListItem* shieldItem =
|
|
new ValueListItem("Shield Options", shield_items, &menu.SHIELD_STATE, "shield", shield_help);
|
|
list->addItem(shieldItem);
|
|
valueListItems.push_back(shieldItem);
|
|
|
|
list->addItem(createBitFlagOption(&menu.MASH_STATE, "Mash Toggles", mash_help));
|
|
|
|
list->addItem(createBitFlagOption(&menu.FOLLOW_UP, "Followup Toggles", follow_up_help));
|
|
|
|
ValueListItem* mashNeutralItem =
|
|
new ValueListItem("Mash In Neutral", on_off, &menu.MASH_IN_NEUTRAL, "mash_neutral", mash_neutral_help);
|
|
list->addItem(mashNeutralItem);
|
|
valueListItems.push_back(mashNeutralItem);
|
|
|
|
list->addItem(createBitFlagOption(&menu.LEDGE_STATE, "Ledge Options", ledge_help));
|
|
|
|
list->addItem(createBitFlagOption(&menu.TECH_STATE, "Tech Options", tech_help));
|
|
|
|
list->addItem(createBitFlagOption(&menu.DEFENSIVE_STATE, "Defensive Options", defensive_help));
|
|
|
|
ValueListItem* diItem = new ValueListItem("Set DI", di_items, &menu.DI_STATE, "di", di_help);
|
|
list->addItem(diItem);
|
|
valueListItems.push_back(diItem);
|
|
|
|
ValueListItem* leftStickItem =
|
|
new ValueListItem("Left Stick", di_items, &menu.LEFT_STICK, "leftStick", left_stick_help);
|
|
list->addItem(leftStickItem);
|
|
valueListItems.push_back(leftStickItem);
|
|
|
|
ValueListItem* oosOffsetItem = new ValueListItem("OOS Offset", number_list, &menu.OOS_OFFSET, "oos", oos_help);
|
|
list->addItem(oosOffsetItem);
|
|
valueListItems.push_back(oosOffsetItem);
|
|
|
|
ValueListItem* reactionTime =
|
|
new ValueListItem("Reaction Time", number_list_big, &menu.REACTION_TIME, "reaction_time", reaction_time_help);
|
|
list->addItem(reactionTime);
|
|
valueListItems.push_back(reactionTime);
|
|
|
|
ValueListItem* fastFallItem = new ValueListItem("Fast Fall", on_off, &menu.FAST_FALL, "fast_fall", "");
|
|
list->addItem(fastFallItem);
|
|
valueListItems.push_back(fastFallItem);
|
|
|
|
ValueListItem* fastFallDelay =
|
|
new ValueListItem("Fast Fall Delay", number_list_big, &menu.FAST_FALL_DELAY, "fast_fall", "In Frames");
|
|
list->addItem(fastFallDelay);
|
|
valueListItems.push_back(fastFallDelay);
|
|
|
|
ValueListItem* fallingAerialsItem =
|
|
new ValueListItem("Falling Aerials", on_off, &menu.FALLING_AERIALS, "falling_aerials", "");
|
|
list->addItem(fallingAerialsItem);
|
|
valueListItems.push_back(fallingAerialsItem);
|
|
|
|
ValueListItem* fullHopItem = new ValueListItem("Full Hop", on_off, &menu.FULL_HOP, "full_hop", "");
|
|
list->addItem(fullHopItem);
|
|
valueListItems.push_back(fullHopItem);
|
|
|
|
ClickableListItem* saveStateItem = new ClickableListItem(
|
|
"Save States", save_state_items, nullptr, "saveStates", 0, "Save States", save_states_help);
|
|
saveStateItem->setClickListener([](std::vector<std::string> values,
|
|
int* curValue,
|
|
std::string extdata,
|
|
int index,
|
|
std::string title,
|
|
std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
saveStateItem->setHelpListener([](std::string title, std::string help) { tsl::changeTo<GuiHelp>(title, help); });
|
|
list->addItem(saveStateItem);
|
|
|
|
rootFrame->setContent(list);
|
|
}
|
|
else
|
|
{
|
|
tsl::elm::Element* warning =
|
|
new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
renderer->drawString("\uE150", false, 180, 250, 90, tsl::Color(255, 255, 255, 255));
|
|
renderer->drawString("Could not debug process memory", false, 110, 340, 25, tsl::Color(255, 255, 255, 255));
|
|
});
|
|
|
|
rootFrame->setContent(warning);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tsl::elm::Element* warning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer* renderer, u16 x, u16 y, u16 w, u16 h) {
|
|
renderer->drawString("\uE150", false, 180, 250, 90, tsl::Color(255, 255, 255, 255));
|
|
renderer->drawString("Smash not running.", false, 110, 340, 25, tsl::Color(255, 255, 255, 255));
|
|
});
|
|
|
|
rootFrame->setContent(warning);
|
|
}
|
|
|
|
return rootFrame;
|
|
}
|
|
|
|
void GuiMain::update()
|
|
{
|
|
static u32 counter = 0;
|
|
|
|
if(counter++ % 15 != 0) return;
|
|
|
|
applyChanges();
|
|
}
|
|
|
|
void GuiMain::applyChanges()
|
|
{
|
|
for(ValueListItem* item : valueListItems)
|
|
{
|
|
item->applyChanges();
|
|
}
|
|
Result rc;
|
|
Handle debug;
|
|
|
|
if(pidSmash != 0)
|
|
{
|
|
rc = svcDebugActiveProcess(&debug, pidSmash);
|
|
if(R_SUCCEEDED(rc))
|
|
{
|
|
u64 menu_addr = 0;
|
|
FsFile menuAddrFile;
|
|
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_LOG, FsOpenMode_Read, &menuAddrFile);
|
|
if(R_FAILED(rc))
|
|
{
|
|
svcCloseHandle(debug);
|
|
return;
|
|
}
|
|
|
|
char buffer[100];
|
|
u64 bytesRead;
|
|
rc = fsFileRead(&menuAddrFile, 0, buffer, 100, FsReadOption_None, &bytesRead);
|
|
if(R_FAILED(rc))
|
|
{
|
|
svcCloseHandle(debug);
|
|
return;
|
|
}
|
|
|
|
fsFileClose(&menuAddrFile);
|
|
buffer[bytesRead] = '\0';
|
|
menu_addr = strtoul(buffer, NULL, 16);
|
|
|
|
if(menu_addr != 0)
|
|
{
|
|
rc = svcWriteDebugProcessMemory(debug, &menu, (u64)menu_addr, sizeof(menu));
|
|
}
|
|
svcCloseHandle(debug);
|
|
}
|
|
}
|
|
|
|
FsFile menuFile;
|
|
fsFsCreateFile(&this->m_fs, TRAINING_MOD_CONF, sizeof(menu), 0);
|
|
|
|
rc = fsFsOpenFile(&this->m_fs, TRAINING_MOD_CONF, FsOpenMode_Write, &menuFile);
|
|
if(R_FAILED(rc))
|
|
{
|
|
fsFileClose(&menuFile);
|
|
return;
|
|
}
|
|
|
|
rc = fsFileWrite(&menuFile, 0, static_cast<void*>(&menu), sizeof(menu), FsOpenMode_Write);
|
|
if(R_FAILED(rc))
|
|
{
|
|
fsFileClose(&menuFile);
|
|
return;
|
|
}
|
|
|
|
fsFileClose(&menuFile);
|
|
} |