#include "prelaunch.hpp" #include "popup.hpp" #include "dusk/config.hpp" #include "dusk/file_select.hpp" #include "dusk/iso_validate.hpp" #include "dusk/main.h" #include "dusk/settings.h" #include "dusk/ui/prelaunch_options.hpp" #include "dusk/ui/preset.hpp" #include "version.h" #include #include #include namespace dusk::ui { const Rml::String kDocumentSource = R"RML(
Twilit Realm presents
Version
Update available! Download
)RML"; constexpr std::array kDiscFileFilters{{ {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, {"All Files", "*"}, }}; static std::string get_error_msg(iso::ValidationError error) { switch (error) { case iso::ValidationError::IOError: return "Unable to read the selected file."; case iso::ValidationError::InvalidImage: return "The selected file is not a valid disc image."; case iso::ValidationError::WrongGame: return "The selected game is not supported by Dusk."; case iso::ValidationError::WrongVersion: return "Dusk currently supports GameCube USA and PAL disc images only."; case iso::ValidationError::Success: return "The selected disc image is valid."; default: return "The selected disc image could not be validated."; } } void file_dialog_callback(void*, const char* path, const char* error) { auto& state = prelaunch_state(); if (error != nullptr) { return; } if (path == nullptr) { return; } const auto validation = iso::validate(path); if (validation != iso::ValidationError::Success) { state.errorString = escape(get_error_msg(validation)); return; } state.selectedDiscPath = path; state.errorString.clear(); getSettings().backend.isoPath.setValue(state.selectedDiscPath); config::Save(); refresh_state(); } PrelaunchState sPrelaunchState; PrelaunchState& prelaunch_state() noexcept { return sPrelaunchState; } void refresh_state() noexcept { auto& state = prelaunch_state(); const auto validation = iso::validate(state.selectedDiscPath.c_str()); if (state.selectedDiscPath.empty() || validation != iso::ValidationError::Success) { state.selectedDiscIsValid = false; return; } state.selectedDiscIsValid = true; state.selectedDiscIsPal = iso::isPal(state.selectedDiscPath.c_str()); } void ensure_initialized() noexcept { auto& state = prelaunch_state(); if (state.initialized) { return; } state.selectedDiscPath = getSettings().backend.isoPath; state.initialDiscPath = state.selectedDiscPath; if (iso::validate(state.initialDiscPath.c_str()) == iso::ValidationError::Success) { state.initialDiscIsPal = iso::isPal(state.initialDiscPath.c_str()); } state.initialLanguage = getSettings().game.language; state.initialGraphicsBackend = getSettings().backend.graphicsBackend; state.initialCardFileType = getSettings().backend.cardFileType; state.errorString.clear(); state.initialized = true; refresh_state(); } void open_iso_picker() noexcept { ensure_initialized(); ShowFileSelect(&file_dialog_callback, nullptr, aurora::window::get_sdl_window(), kDiscFileFilters.data(), kDiscFileFilters.size(), nullptr, false); } bool is_restart_pending() noexcept { const auto& state = prelaunch_state(); if (!state.initialDiscPath.empty() && state.selectedDiscPath != state.initialDiscPath) { return true; } if (getSettings().backend.graphicsBackend.getValue() != state.initialGraphicsBackend) { return true; } if (getSettings().game.language.getValue() != state.initialLanguage) { return true; } if (getSettings().backend.cardFileType.getValue() != state.initialCardFileType) { return true; } return false; } void apply_intro_animation(Rml::Element* element, const char* delay_class) { if (element == nullptr || delay_class == nullptr) { return; } element->SetClass("intro-item", true); element->SetClass(delay_class, true); } void try_apply_mirrored_layout(Rml::Element* body) { if (body == nullptr) { return; } body->SetClass("mirrored", getSettings().game.enableMirrorMode.getValue()); } Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementById("root")) { ensure_initialized(); if (auto* menuList = mDocument->GetElementById("menu-list")) { auto& state = prelaunch_state(); mMenuButtons.push_back( std::make_unique