Work on better Cache save support.

This commit is contained in:
J-D-K 2025-10-05 11:38:54 -04:00
parent b845aa886a
commit 8d449685bd
21 changed files with 174 additions and 92 deletions

View File

@ -138,6 +138,9 @@
"RemotePops": [
"0: No internet connection available!"
],
"SaveCreateConfs":[
"This is a cache type save. Would you like to create it on the SD card instead of NAND?"
],
"SaveCreatePops": [
"0: Save data created for #%s#!",
"1: Error creating save data!",

View File

@ -39,7 +39,8 @@ class ConfirmState final : public BaseState
/// @param dataStruct shared_ptr<StructType> that is passed to function. I tried templating this and it was a nightmare.
ConfirmState(std::string_view query,
bool holdRequired,
sys::threadpool::JobFunction function,
sys::threadpool::JobFunction onConfirm,
sys::threadpool::JobFunction onCancel,
sys::Task::TaskData taskData)
: BaseState(false)
, m_query(query)
@ -47,7 +48,8 @@ class ConfirmState final : public BaseState
, m_noText(strings::get_by_name(strings::names::YES_NO_OK, 1))
, m_holdRequired(holdRequired)
, m_transition(280, 229, 32, 32, 280, 229, 720, 256, 4)
, m_function(function)
, m_onConfirm(onConfirm)
, m_onCancel(onCancel)
, m_taskData(taskData)
{
ConfirmState::initialize_static_members();
@ -59,20 +61,22 @@ class ConfirmState final : public BaseState
/// @brief Returns a new ConfirmState. See constructor.
static inline std::shared_ptr<ConfirmState> create(std::string_view query,
bool holdRequired,
sys::threadpool::JobFunction function,
sys::threadpool::JobFunction onConfirm,
sys::threadpool::JobFunction onCancel,
sys::Task::TaskData taskData)
{
return std::make_shared<ConfirmState>(query, holdRequired, function, taskData);
return std::make_shared<ConfirmState>(query, holdRequired, onConfirm, onCancel, taskData);
}
/// @brief Creates and returns a new ConfirmState and pushes it.
static inline std::shared_ptr<ConfirmState> create_and_push(std::string_view query,
bool holdRequired,
sys::threadpool::JobFunction function,
sys::threadpool::JobFunction onConfirm,
sys::threadpool::JobFunction onCancel,
sys::Task::TaskData taskData)
{
// I'm gonna use a sneaky trick here. This shouldn't do this because it's confusing.
auto newState = create(query, holdRequired, function, taskData);
auto newState = create(query, holdRequired, onConfirm, onCancel, taskData);
StateManager::push_state(newState);
return newState;
}
@ -80,10 +84,11 @@ class ConfirmState final : public BaseState
/// @brief Same as above but with a fade transition pushed in between.
static std::shared_ptr<ConfirmState> create_push_fade(std::string_view query,
bool holdRequired,
sys::threadpool::JobFunction function,
sys::threadpool::JobFunction onConfirm,
sys::threadpool::JobFunction onCancel,
sys::Task::TaskData taskData)
{
auto newState = ConfirmState::create(query, holdRequired, function, taskData);
auto newState = ConfirmState::create(query, holdRequired, onConfirm, onCancel, taskData);
FadeState::create_and_push(colors::DIM_BACKGROUND, colors::ALPHA_FADE_BEGIN, colors::ALPHA_FADE_END, newState);
return newState;
}
@ -167,7 +172,10 @@ class ConfirmState final : public BaseState
bool m_close{};
/// @brief Function to execute if action is confirmed.
const sys::threadpool::JobFunction m_function{};
const sys::threadpool::JobFunction m_onConfirm{};
/// @brief Function to execute if action is cancelled.
const sys::threadpool::JobFunction m_onCancel{};
/// @brief Pointer to data struct passed to ^
const sys::Task::TaskData m_taskData{};
@ -235,8 +243,10 @@ class ConfirmState final : public BaseState
void deactivate_state()
{
if (m_confirmed) { StateType::create_and_push(m_function, m_taskData); }
else {
if (m_confirmed && m_onConfirm) { StateType::create_and_push(m_onConfirm, m_taskData); }
else if (!m_confirmed && m_onCancel) { StateType::create_and_push(m_onCancel, m_taskData); }
else
{
FadeState::create_and_push(colors::DIM_BACKGROUND, colors::ALPHA_FADE_END, colors::ALPHA_FADE_BEGIN, nullptr);
}
BaseState::deactivate();

View File

@ -45,6 +45,7 @@ class SaveCreateState final : public BaseState
{
data::User *user{};
data::TitleInfo *titleInfo{};
uint16_t saveDataIndex{}; // This is only used for cache type saves.
SaveCreateState *spawningState{};
};
// clang-format on

View File

@ -15,18 +15,22 @@ class TitleInfoState final : public BaseState
/// @brief Constructs a new title info state.
/// @param user User to display info for.
/// @param titleInfo Title to display info for.
TitleInfoState(data::User *user, data::TitleInfo *titleInfo);
TitleInfoState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo);
/// @brief Creates a new TitleInfoState.
static inline std::shared_ptr<TitleInfoState> create(data::User *user, data::TitleInfo *titleInfo)
static inline std::shared_ptr<TitleInfoState> create(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo)
{
return std::make_shared<TitleInfoState>(user, titleInfo);
return std::make_shared<TitleInfoState>(user, titleInfo, saveInfo);
}
/// @brief Creates, pushes, and returns a new TitleInfoState.
static inline std::shared_ptr<TitleInfoState> create_and_push(data::User *user, data::TitleInfo *titleInfo)
static inline std::shared_ptr<TitleInfoState> create_and_push(data::User *user,
data::TitleInfo *titleInfo,
const FsSaveDataInfo *saveInfo)
{
auto newState = TitleInfoState::create(user, titleInfo);
auto newState = TitleInfoState::create(user, titleInfo, saveInfo);
StateManager::push_state(newState);
return newState;
}
@ -44,6 +48,9 @@ class TitleInfoState final : public BaseState
/// @brief Pointer to title info.
data::TitleInfo *m_titleInfo{};
/// @brief Save a pointer to the save info.
const FsSaveDataInfo *m_saveInfo{};
/// @brief This is a pointer to the title's icon.
sdl::SharedTexture m_icon{};

View File

@ -52,7 +52,7 @@ namespace data
/// @brief Pushes data to m_userData
/// @param saveInfo SaveDataInfo.
/// @param playStats Play statistics.
void add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats);
void add_data(uint64_t applicationID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats);
/// @brief Clears the user save info vector.
void clear_data_entries() noexcept;

View File

@ -9,8 +9,13 @@ namespace fs
/// @brief Creates save data for the target user for the title passed.
/// @param targetUser User to create save data for.
/// @param titleInfo Title to create save data for.
/// @param saveDataIndex Index. Only applicable to cache saves.
/// @param spaceID Save data space ID to create with. Default is 1/User.
/// @return True on success. False on failure.
bool create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept;
bool create_save_data_for(data::User *targetUser,
data::TitleInfo *titleInfo,
uint16_t saveDataIndex = 0,
uint8_t spaceID = 1) noexcept;
/// @brief Creates save data for the user passed using the meta data passed.
bool create_save_data_for(data::User *targetUser, const fs::SaveMetaData &saveMeta) noexcept;

View File

@ -26,6 +26,7 @@ namespace strings::names
inline constexpr std::string_view MAINMENU_POPS = "MainMenuPops";
inline constexpr std::string_view ON_OFF = "OnOff";
inline constexpr std::string_view REMOTE_POPS = "RemotePops";
inline constexpr std::string_view SAVECREATE_CONFS = "SaveCreateConfs";
inline constexpr std::string_view SAVECREATE_POPS = "SaveCreatePops";
inline constexpr std::string_view SAVE_DATA_TYPES = "SaveDataTypes";
inline constexpr std::string_view SETTINGS_DESCRIPTIONS = "SettingsDescriptions";

View File

@ -5,5 +5,11 @@
namespace tasks::savecreate
{
/// @brief Default save creating task.
/// @param taskData Data to pass to thread.
void create_save_data_for(sys::threadpool::JobData taskData);
/// @brief Same as above, but creates the save on the SD card instead. Only used for cache type saves.
/// @param taskData Data to pass to thread.kl;'
void create_save_data_for_sd(sys::threadpool::JobData taskData);
}

View File

@ -264,7 +264,7 @@ void BackupMenuState::confirm_overwrite()
const char *itemName = m_dataStruct->remoteItem->get_name().data();
const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, m_dataStruct);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, nullptr, m_dataStruct);
}
else if (entry.type == MenuEntryType::Local)
{
@ -272,7 +272,7 @@ void BackupMenuState::confirm_overwrite()
const char *targetName = m_directoryListing[entry.index].get_filename();
const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, m_dataStruct);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, nullptr, m_dataStruct);
}
}
@ -312,7 +312,7 @@ void BackupMenuState::confirm_restore()
const char *targetName = m_directoryListing[entry.index].get_filename();
const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, m_dataStruct);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, nullptr, m_dataStruct);
}
else if (entry.type == MenuEntryType::Remote)
{
@ -321,7 +321,7 @@ void BackupMenuState::confirm_restore()
m_dataStruct->remoteItem = target;
m_dataStruct->path = m_directoryPath + "//"; // To-do: This is a workaround.
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, m_dataStruct);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, nullptr, m_dataStruct);
}
}
@ -338,7 +338,7 @@ void BackupMenuState::confirm_delete()
const char *targetName = m_directoryListing[entry.index].get_filename();
const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName);
ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_local, m_dataStruct);
ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_local, nullptr, m_dataStruct);
}
else if (entry.type == MenuEntryType::Remote)
{
@ -346,7 +346,7 @@ void BackupMenuState::confirm_delete()
const char *itemName = m_dataStruct->remoteItem->get_name().data();
const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName);
ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_remote, m_dataStruct);
ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_remote, nullptr, m_dataStruct);
}
}
@ -380,7 +380,7 @@ void BackupMenuState::upload_backup()
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE);
m_dataStruct->remoteItem = remoteItem;
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, m_dataStruct);
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, nullptr, m_dataStruct);
}
else { ProgressState::create_push_fade(tasks::backup::upload_backup, m_dataStruct); }
}

View File

@ -15,7 +15,7 @@ FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, i
: m_mountA(mountA)
, m_mountB(mountB)
, m_journalSize(journalSize)
, m_transition(15, 720, 0, 0, 15, 87, 0, 0, ui::Transition::DEFAULT_THRESHOLD)
, m_transition(15, 720, 0, 0, 15, 89, 0, 0, ui::Transition::DEFAULT_THRESHOLD)
, m_isSystem(isSystem)
, m_allowSystem(config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM))
{
@ -91,11 +91,8 @@ void FileModeState::initialize_static_members()
void FileModeState::initialize_paths()
{
const std::string pathA = m_mountA + ":/";
const std::string pathB = m_mountB + ":/";
m_pathA = pathA;
m_pathB = pathB;
m_pathA = m_mountA + ":/";
m_pathB = m_mountB + ":/";
}
void FileModeState::initialize_menus()
@ -133,6 +130,7 @@ void FileModeState::initialize_directory_menu(const fslib::Path &path, fslib::Di
void FileModeState::hide_dialog() noexcept
{
if (!m_transition.in_place()) { return; }
sm_controlGuide->reset();
m_transition.set_target_y(720);
m_close = true;
}
@ -205,7 +203,6 @@ fslib::Directory &FileModeState::get_destination_directory() noexcept { return m
void FileModeState::deactivate_state() noexcept
{
sm_frame->set_y(720);
sm_controlGuide->reset();
fslib::close_file_system(m_mountA);
fslib::close_file_system(m_mountB);
BaseState::deactivate();

View File

@ -214,7 +214,7 @@ void FileOptionState::copy_target()
const char *copyFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 0);
const std::string query = stringutil::get_formatted_string(copyFormat, sourceString.c_str(), destString.c_str());
ConfirmProgress::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, m_dataStruct);
ConfirmProgress::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, nullptr, m_dataStruct);
}
void FileOptionState::delete_target()
@ -245,7 +245,7 @@ void FileOptionState::delete_target()
m_dataStruct->sourcePath = std::move(fullTarget);
m_dataStruct->journalSize = m_spawningState->m_journalSize;
ConfirmTask::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, m_dataStruct);
ConfirmTask::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, nullptr, m_dataStruct);
}
void FileOptionState::rename_target()

View File

@ -177,9 +177,9 @@ void MainMenuState::backup_all_for_all()
const char *query = strings::get_by_name(strings::names::MAINMENU_CONFS, 0);
if (remote && autoUpload)
{
ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_remote, m_dataStruct);
ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_remote, nullptr, m_dataStruct);
}
else { ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_local, m_dataStruct); }
else { ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_local, nullptr, m_dataStruct); }
}
void MainMenuState::confirm_update()
@ -187,5 +187,5 @@ void MainMenuState::confirm_update()
const char *confirmUpdate = strings::get_by_name(strings::names::UPDATE_CONFIRMATION, 0);
auto taskData = std::make_shared<sys::Task::DataStruct>();
ConfirmProgress::create_push_fade(confirmUpdate, false, tasks::update::download_update, taskData);
ConfirmProgress::create_push_fade(confirmUpdate, false, tasks::update::download_update, nullptr, taskData);
}

View File

@ -1,11 +1,12 @@
#include "appstates/SaveCreateState.hpp"
#include "StateManager.hpp"
#include "appstates/TaskState.hpp"
#include "appstates/ConfirmState.hpp"
#include "data/data.hpp"
#include "error.hpp"
#include "fs/fs.hpp"
#include "input.hpp"
#include "keyboard.hpp"
#include "logging/logger.hpp"
#include "strings/strings.hpp"
#include "stringutil.hpp"
@ -97,11 +98,29 @@ void SaveCreateState::initialize_data_struct()
void SaveCreateState::create_save_data_for()
{
static constexpr std::string_view DEFAULT_INDEX = "0";
char cacheIndex[3] = {0};
const int selected = m_saveMenu->get_selected();
data::TitleInfo *titleInfo = m_titleInfoVector[selected];
m_dataStruct->titleInfo = titleInfo;
TaskState::create_and_push(tasks::savecreate::create_save_data_for, m_dataStruct);
const char *keyboardString = strings::get_by_name(strings::names::KEYBOARD, 1);
const bool isCache = m_user->get_account_save_type() == FsSaveDataType_Cache;
const bool indexInput = isCache && keyboard::get_input(SwkbdType_QWERTY, DEFAULT_INDEX, keyboardString, cacheIndex, 3);
if (isCache && !indexInput) { return; }
else if (isCache && indexInput) { m_dataStruct->saveDataIndex = std::strtoul(cacheIndex, nullptr, 10); }
if (!isCache) { TaskState::create_and_push(tasks::savecreate::create_save_data_for, m_dataStruct); }
else
{
const char *confirmString = strings::get_by_name(strings::names::SAVECREATE_CONFS, 0);
ConfirmTask::create_push_fade(confirmString,
false,
tasks::savecreate::create_save_data_for_sd,
tasks::savecreate::create_save_data_for,
m_dataStruct);
}
}
void SaveCreateState::deactivate_state()

View File

@ -76,7 +76,7 @@ void SaveImportState::import_backup()
const char *confirmFormat = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 1);
std::string query = stringutil::get_formatted_string(confirmFormat, targetName);
ConfirmProgress::create_and_push(query, holdRequired, tasks::saveimport::import_save_backup, sm_taskData);
ConfirmProgress::create_and_push(query, holdRequired, tasks::saveimport::import_save_backup, nullptr, sm_taskData);
}
void SaveImportState::deactivate_state()

View File

@ -25,9 +25,10 @@ namespace
constexpr int SIZE_TEXT_TARGET_HEIGHT = 40;
} // namespace
TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo)
TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo)
: m_user(user)
, m_titleInfo(titleInfo)
, m_saveInfo(saveInfo)
, m_icon(m_titleInfo->get_icon())
{
TitleInfoState::initialize_static_members();
@ -71,7 +72,7 @@ void TitleInfoState::create_info_scrolls()
static constexpr int COORD_INIT_Y = 278;
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
const FsSaveDataInfo *saveInfo = m_saveInfo;
const PdmPlayStatistics *playStats = m_user->get_play_stats_by_id(applicationID);
if (error::is_null(saveInfo) || error::is_null(playStats)) { return; }

View File

@ -136,8 +136,8 @@ void TitleOptionState::initialize_data_struct()
void TitleOptionState::create_push_info_state()
{
sm_slidePanel->hide();
auto titleInfoState = TitleInfoState::create(m_user, m_titleInfo);
StateManager::push_state(titleInfoState);
TitleInfoState::create_and_push(m_user, m_titleInfo, m_saveInfo);
}
void TitleOptionState::add_to_blacklist()
@ -146,7 +146,7 @@ void TitleOptionState::add_to_blacklist()
const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 0);
const std::string query = stringutil::get_formatted_string(confirmFormat, title);
ConfirmTask::create_push_fade(query, false, tasks::titleoptions::blacklist_title, m_dataStruct);
ConfirmTask::create_push_fade(query, false, tasks::titleoptions::blacklist_title, nullptr, m_dataStruct);
}
void TitleOptionState::change_output_directory()
@ -201,23 +201,18 @@ void TitleOptionState::change_output_directory()
void TitleOptionState::create_push_file_mode()
{
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
const data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo);
const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *m_saveInfo);
if (!saveOpened) { return; }
const FsSaveDataType saveType = m_user->get_account_save_type();
const bool isSystem = saveType == FsSaveDataType_System || saveType == FsSaveDataType_SystemBcat;
FsSaveDataExtraData extraData{};
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType);
const bool readExtra = fs::read_save_extra_data(m_saveInfo, extraData);
const int64_t journalSize = readExtra ? extraData.journal_size : m_titleInfo->get_journal_size(saveType);
sm_slidePanel->hide();
FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", journalSize, isSystem);
sm_slidePanel->hide();
}
void TitleOptionState::delete_all_local_backups()
@ -226,7 +221,7 @@ void TitleOptionState::delete_all_local_backups()
const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 1);
const std::string query = stringutil::get_formatted_string(confirmFormat, title);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_local_backups_for_title, m_dataStruct);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_local_backups_for_title, nullptr, m_dataStruct);
}
void TitleOptionState::delete_all_remote_backups()
@ -235,18 +230,14 @@ void TitleOptionState::delete_all_remote_backups()
const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 1);
const std::string query = stringutil::get_formatted_string(confirmFormat, title);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_remote_backups_for_title, m_dataStruct);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_remote_backups_for_title, nullptr, m_dataStruct);
}
void TitleOptionState::reset_save_data()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const bool allowSystemWriting = config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM);
if (!allowSystemWriting && fs::is_system_save_data(saveInfo))
if (!allowSystemWriting && fs::is_system_save_data(m_saveInfo))
{
const char *popNoSysWrite = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6);
ui::PopMessageManager::push_message(popTicks, popNoSysWrite);
@ -257,18 +248,15 @@ void TitleOptionState::reset_save_data()
const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 2);
const std::string query = stringutil::get_formatted_string(confirmFormat, title);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::reset_save_data, m_dataStruct);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::reset_save_data, nullptr, m_dataStruct);
}
void TitleOptionState::delete_save_from_system()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
// This isn't allowed at ALL.
if (fs::is_system_save_data(saveInfo))
if (fs::is_system_save_data(m_saveInfo))
{
const char *popUnavailable = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6);
ui::PopMessageManager::push_message(popTicks, popUnavailable);
@ -280,17 +268,14 @@ void TitleOptionState::delete_save_from_system()
const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 3);
const std::string query = stringutil::get_formatted_string(confirmFormat, nickname, title);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_save_data_from_system, m_dataStruct);
ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_save_data_from_system, nullptr, m_dataStruct);
}
void TitleOptionState::extend_save_container()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
if (fs::is_system_save_data(saveInfo))
if (fs::is_system_save_data(m_saveInfo))
{
const char *popUnavailable = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6);
ui::PopMessageManager::push_message(popTicks, popUnavailable);

View File

@ -127,9 +127,12 @@ void UserOptionState::backup_all()
const std::string query = stringutil::get_formatted_string(confirmFormat, nickname);
if (remote && autoUpload)
{
ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_remote, m_dataStruct);
ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_remote, nullptr, m_dataStruct);
}
else
{
ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_local, nullptr, m_dataStruct);
}
else { ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); }
}
void UserOptionState::create_save_create()
@ -148,7 +151,7 @@ void UserOptionState::create_all_save_data()
const char *nickname = m_user->get_nickname();
const std::string query = stringutil::get_formatted_string(confirmFormat, nickname);
ConfirmTask::create_push_fade(query, true, tasks::useroptions::create_all_save_data_for_user, m_dataStruct);
ConfirmTask::create_push_fade(query, true, tasks::useroptions::create_all_save_data_for_user, nullptr, m_dataStruct);
}
void UserOptionState::delete_all_save_data()
@ -159,7 +162,7 @@ void UserOptionState::delete_all_save_data()
const char *confirmFormat = strings::get_by_name(strings::names::USEROPTION_CONFS, 2);
const char *nickname = m_user->get_nickname();
const std::string queryString = stringutil::get_formatted_string(confirmFormat, nickname);
ConfirmTask::create_push_fade(queryString, true, tasks::useroptions::delete_all_save_data_for_user, m_dataStruct);
ConfirmTask::create_push_fade(queryString, true, tasks::useroptions::delete_all_save_data_for_user, nullptr, m_dataStruct);
}
void UserOptionState::create_push_save_import()

View File

@ -19,7 +19,7 @@ namespace
constexpr int SIZE_ICON_FONT = 50;
/// @brief This is the number of FsSaveDataInfo entries to allocate and try to read.
constexpr size_t SIZE_SAVE_INFO_BUFFER = 256;
constexpr size_t SIZE_SAVE_INFO_BUFFER = 128;
// Array of SaveDataSpaceIDs - SaveDataSpaceAll doesn't seem to work as it should...
constexpr std::array<FsSaveDataSpaceId, 6> SAVE_DATA_SPACE_ORDER = {FsSaveDataSpaceId_System,
@ -78,13 +78,9 @@ data::User &data::User::operator=(data::User &&user) noexcept
return *this;
}
void data::User::add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats)
void data::User::add_data(uint64_t applicationID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats)
{
const uint64_t saveInfoAppID = saveInfo->application_id;
const uint64_t saveInfoSysID = saveInfo->system_save_data_id;
const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID;
auto dataPair = std::make_pair(*saveInfo, *playStats);
auto dataPair = std::make_pair(saveInfo, playStats);
auto vectorPair = std::make_pair(applicationID, std::move(dataPair));
m_userData.push_back(std::move(vectorPair));
}
@ -180,9 +176,10 @@ void data::User::load_user_data()
bool mounted{};
if (!isBlacklisted && !systemFilter && enforceMount)
{
fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, &saveInfo, false};
fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, &saveInfo};
mounted = saveMount.is_open();
}
if (isBlacklisted || systemFilter || (enforceMount && !mounted)) { continue; }
const bool titleFound = data::title_exists_in_map(applicationID);
@ -194,10 +191,12 @@ void data::User::load_user_data()
m_accountID,
false,
&playStats);
User::add_data(&saveInfo, &playStats);
User::add_data(applicationID, saveInfo, playStats);
}
}
}
User::sort_data();
}

View File

@ -8,7 +8,10 @@ namespace
inline constexpr FsSaveDataMetaInfo SAVE_CREATE_META = {.size = 0x40060, .type = FsSaveDataMetaType_Thumbnail};
}
bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept
bool fs::create_save_data_for(data::User *targetUser,
data::TitleInfo *titleInfo,
uint16_t saveDataIndex,
uint8_t spaceID) noexcept
{
const uint8_t saveType = targetUser->get_account_save_type();
@ -23,14 +26,14 @@ bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo
.system_save_data_id = 0,
.save_data_type = saveType,
.save_data_rank = FsSaveDataRank_Primary,
.save_data_index = 0};
.save_data_index = saveDataIndex};
const FsSaveDataCreationInfo saveCreation = {.save_data_size = saveSize,
.journal_size = journalSize,
.available_size = 0x4000,
.owner_id = ownerID,
.flags = 0,
.save_data_space_id = FsSaveDataSpaceId_User};
.save_data_space_id = spaceID};
// I want this recorded.
return error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &SAVE_CREATE_META)) == false;

View File

@ -15,6 +15,9 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData)
data::TitleInfo *titleInfo = castData->titleInfo;
SaveCreateState *spawningState = castData->spawningState;
const bool isCache = user->get_account_save_type() == FsSaveDataType_Cache;
const uint16_t saveIndex = isCache ? castData->saveDataIndex : 0;
if (error::is_null(task)) { return; }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
@ -29,7 +32,7 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData)
task->set_status(status);
}
const bool saveCreated = fs::create_save_data_for(user, titleInfo);
const bool saveCreated = fs::create_save_data_for(user, titleInfo, saveIndex);
if (!saveCreated) { ui::PopMessageManager::push_message(popTicks, popFailed); }
else
{
@ -40,3 +43,41 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData)
task->complete();
}
void tasks::savecreate::create_save_data_for_sd(sys::threadpool::JobData taskData)
{
auto castData = std::static_pointer_cast<SaveCreateState::DataStruct>(taskData);
sys::Task *task = castData->task;
data::User *user = castData->user;
data::TitleInfo *titleInfo = castData->titleInfo;
SaveCreateState *spawningState = castData->spawningState;
bool isCache = user->get_account_save_type() == FsSaveDataType_Cache;
const uint16_t saveIndex = isCache ? castData->saveDataIndex : 0;
if (error::is_null(task)) { return; }
else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const char *statusFormat = strings::get_by_name(strings::names::USEROPTION_STATUS, 0);
const char *popSuccess = strings::get_by_name(strings::names::SAVECREATE_POPS, 0);
const char *popFailed = strings::get_by_name(strings::names::SAVECREATE_POPS, 1);
const char *title = titleInfo->get_title();
{
std::string status = stringutil::get_formatted_string(statusFormat, title);
task->set_status(status);
}
const bool saveCreated = fs::create_save_data_for(user, titleInfo, saveIndex, 4);
if (!saveCreated) { ui::PopMessageManager::push_message(popTicks, popFailed); }
else
{
std::string popMessage = stringutil::get_formatted_string(popSuccess, title);
ui::PopMessageManager::push_message(popTicks, popMessage);
spawningState->refresh_required();
}
task->complete();
}

View File

@ -104,7 +104,8 @@ void ui::Menu::reset(bool full)
if (full)
{
m_selected = 0;
m_y = m_originalY;
m_transition.set_y(m_originalY);
m_transition.set_target_y(m_originalY);
}
m_options.clear();