1
0
Fork 0
mirror of https://github.com/jugeeya/UltimateTrainingModpack.git synced 2025-04-26 15:39:17 +00:00
UltimateTrainingModpack/TrainingModpackOverlay/source/gui_main.cpp
sidschingis 7ff8185a65
Apply Bit Flags to Mash/Defensive Options (#136)
* Apply Bit Flag

Defensive Options

* Apply Bit Flag

Followups

* Apply Bit Flag

Mash options

* Update Version String
2020-08-14 12:12:50 -07:00

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