JKSV/source/JKSV.cpp

226 lines
7.0 KiB
C++

#include "JKSV.hpp"
#include "StateManager.hpp"
#include "appstates/MainMenuState.hpp"
#include "colors.hpp"
#include "config.hpp"
#include "curl/curl.hpp"
#include "data/data.hpp"
#include "fslib.hpp"
#include "input.hpp"
#include "logger.hpp"
#include "remote/remote.hpp"
#include "sdl.hpp"
#include "strings.hpp"
#include "ui/PopMessageManager.hpp"
#include <switch.h>
// Normally I try to avoid C macros in C++, but this cleans stuff up nicely.
#define ABORT_ON_FAILURE(x) \
if (!x) \
{ \
return; \
}
namespace
{
/// @brief Build month.
constexpr uint8_t BUILD_MON = 6;
/// @brief Build day.
constexpr uint8_t BUILD_DAY = 13;
/// @brief Year.
constexpr uint16_t BUILD_YEAR = 2025;
} // namespace
template <typename... Args>
static bool initialize_service(Result (*function)(Args...), const char *serviceName, Args... args)
{
Result error = (*function)(args...);
if (R_FAILED(error))
{
logger::log("Error initializing %s: 0x%X.", error);
return false;
}
return true;
}
JKSV::JKSV()
{
// Start with this.
appletSetCpuBoostMode(ApmCpuBoostMode_FastLoad);
// FsLib
ABORT_ON_FAILURE(fslib::initialize());
// This doesn't rely on stdio or anything.
logger::initialize();
// Need to init RomFS here for now until I update FsLib to take care of this. Never mind. That isn't going to happen.
ABORT_ON_FAILURE(initialize_service(romfsInit, "RomFS"));
// Let FsLib take care of calls to SDMC instead of fs_dev
ABORT_ON_FAILURE(fslib::dev::initialize_sdmc());
// SDL
ABORT_ON_FAILURE(sdl::initialize("JKSV", 1280, 720));
ABORT_ON_FAILURE(sdl::text::initialize());
// Services.
// Using administrator so JKSV can still run in Applet mode, barely.
ABORT_ON_FAILURE(initialize_service(accountInitialize, "Account", AccountServiceType_Administrator));
ABORT_ON_FAILURE(initialize_service(nsInitialize, "NS"));
ABORT_ON_FAILURE(initialize_service(pdmqryInitialize, "PDMQry"));
ABORT_ON_FAILURE(initialize_service(plInitialize, "PL", PlServiceType_User));
ABORT_ON_FAILURE(initialize_service(pmshellInitialize, "PMShell"));
ABORT_ON_FAILURE(initialize_service(setInitialize, "Set"));
ABORT_ON_FAILURE(initialize_service(setsysInitialize, "SetSys"));
ABORT_ON_FAILURE(initialize_service(socketInitializeDefault, "Socket"));
ABORT_ON_FAILURE(curl::initialize());
// Input doesn't have anything to return.
input::initialize();
// Neither does config.
config::initialize();
// Get and create working directory. There isn't much of an FS anymore.
fslib::Path workingDirectory = config::get_working_directory();
if (!fslib::directory_exists(workingDirectory) && !fslib::create_directories_recursively(workingDirectory))
{
logger::log("Error creating working directory: %s", fslib::error::get_string());
return;
}
// I'd rather this be here than checked every time one is exported.
fslib::Path sviDir = config::get_working_directory() / "svi";
if (!fslib::directory_exists(sviDir) && !fslib::create_directories_recursively(sviDir))
{
// This one isn't fatal, but it can be super fatal later if this fails.
logger::log("Error creating svi directory: %s", fslib::error::get_string());
}
// JKSV also has no internal strings anymore. This is FATAL now.
ABORT_ON_FAILURE(strings::initialize());
if (!data::initialize(false))
{
return;
}
// Install/setup our color changing characters.
sdl::text::add_color_character(L'#', colors::BLUE);
sdl::text::add_color_character(L'*', colors::RED);
sdl::text::add_color_character(L'<', colors::YELLOW);
sdl::text::add_color_character(L'>', colors::GREEN);
sdl::text::add_color_character(L'`', colors::BLUE_GREEN);
sdl::text::add_color_character(L'^', colors::PINK);
// This is to check whether the author wanted credit for their work.
m_showTranslationInfo =
std::char_traits<char>::compare(strings::get_by_name(strings::names::TRANSLATION_INFO, 1), "NULL", 4) != 0;
// This can't be in an initializer list because it needs SDL initialized.
m_headerIcon = sdl::TextureManager::create_load_texture("HeaderIcon", "romfs:/Textures/HeaderIcon.png");
// Push initial main menu state.
StateManager::push_state(std::make_shared<MainMenuState>());
if (fslib::file_exists(remote::PATH_GOOGLE_DRIVE_CONFIG))
{
remote::initialize_google_drive();
}
else if (fslib::file_exists(remote::PATH_WEBDAV_CONFIG))
{
remote::initialize_webdav();
}
m_isRunning = true;
}
JKSV::~JKSV()
{
// Try to save config first.
config::save();
curl::exit();
socketExit();
setsysExit();
setExit();
pmshellExit();
plExit();
pdmqryExit();
nsExit();
accountExit();
sdl::text::exit();
sdl::exit();
fslib::exit();
appletSetCpuBoostMode(ApmCpuBoostMode_Normal);
}
bool JKSV::is_running() const
{
return m_isRunning;
}
void JKSV::update()
{
input::update();
if (input::button_pressed(HidNpadButton_Plus) && StateManager::back_is_closable())
{
m_isRunning = false;
}
// State update.
StateManager::update();
// Update pop messages.
ui::PopMessageManager::update();
}
void JKSV::render()
{
sdl::frame_begin(colors::CLEAR_COLOR);
// Top and bottom divider lines.
sdl::render_line(NULL, 30, 88, 1250, 88, colors::WHITE);
sdl::render_line(NULL, 30, 648, 1250, 648, colors::WHITE);
// Icon
m_headerIcon->render(NULL, 66, 27);
// "JKSV"
sdl::text::render(NULL, 130, 32, 34, sdl::text::NO_TEXT_WRAP, colors::WHITE, "JKSV");
// Translation info in bottom left.
if (m_showTranslationInfo)
{
sdl::text::render(NULL,
8,
680,
14,
sdl::text::NO_TEXT_WRAP,
colors::WHITE,
strings::get_by_name(strings::names::TRANSLATION_INFO, 0),
strings::get_by_name(strings::names::TRANSLATION_INFO, 1));
}
// Build date
sdl::text::render(NULL,
8,
700,
14,
sdl::text::NO_TEXT_WRAP,
colors::WHITE,
"v. %02d.%02d.%04d",
BUILD_MON,
BUILD_DAY,
BUILD_YEAR);
// State render.
StateManager::render();
// Render messages.
ui::PopMessageManager::render();
sdl::frame_end();
}