Merge pull request #3665 from bunnei/device-save

FS: Improve emulation of device saves
This commit is contained in:
bunnei 2020-05-16 12:39:58 -04:00 committed by GitHub
commit 65010607b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 98 additions and 31 deletions

View File

@ -95,6 +95,10 @@ u32 NACP::GetSupportedLanguages() const {
return raw.supported_languages; return raw.supported_languages;
} }
u64 NACP::GetDeviceSaveDataSize() const {
return raw.device_save_data_size;
}
std::vector<u8> NACP::GetRawBytes() const { std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP)); std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP)); std::memcpy(out.data(), &raw, sizeof(RawNACP));

View File

@ -113,6 +113,7 @@ public:
u32 GetSupportedLanguages() const; u32 GetSupportedLanguages() const;
std::vector<u8> GetRawBytes() const; std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const; bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const;
private: private:
RawNACP raw{}; RawNACP raw{};

View File

@ -57,7 +57,8 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) {
return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage ||
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0); (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) &&
desc.title_id == 0 && desc.save_id == 0);
} }
} // Anonymous namespace } // Anonymous namespace
@ -139,8 +140,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
u128 user_id, u64 save_id) { u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process. // be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData && title_id == 0) { if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); if (title_id == 0) {
title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
}
} }
std::string out = GetSaveDataSpaceIdPath(space); std::string out = GetSaveDataSpaceIdPath(space);

View File

@ -767,7 +767,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
{1014, nullptr, "OutputMultiProgramTagAccessLog"}, {1014, nullptr, "OutputMultiProgramTagAccessLog"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
{1200, nullptr, "OpenMultiCommitManager"}, {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
{1300, nullptr, "OpenBisWiper"}, {1300, nullptr, "OpenBisWiper"},
}; };
// clang-format on // clang-format on
@ -988,4 +988,40 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
rb.Push(access_log_program_index); rb.Push(access_log_program_index);
} }
class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
public:
explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") {
static const FunctionInfo functions[] = {
{1, &IMultiCommitManager::Add, "Add"},
{2, &IMultiCommitManager::Commit, "Commit"},
};
RegisterHandlers(functions);
}
private:
FileSys::VirtualFile backend;
void Add(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Commit(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
};
void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>());
}
} // namespace Service::FileSystem } // namespace Service::FileSystem

View File

@ -50,6 +50,7 @@ private:
void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
FileSystemController& fsc; FileSystemController& fsc;

View File

@ -488,11 +488,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string pat
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
connect(open_save_location, &QAction::triggered, [this, program_id]() { connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); emit OpenFolderRequested(GameListOpenTarget::SaveData, path);
}); });
connect(open_lfs_location, &QAction::triggered, [this, program_id]() { connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); emit OpenFolderRequested(GameListOpenTarget::ModData, path);
}); });
connect(open_transferable_shader_cache, &QAction::triggered, connect(open_transferable_shader_cache, &QAction::triggered,
[this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); });

View File

@ -73,7 +73,7 @@ public:
signals: signals:
void GameChosen(QString game_path); void GameChosen(QString game_path);
void ShouldCancelWorker(); void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target); void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path);
void OpenTransferableShaderCacheRequested(u64 program_id); void OpenTransferableShaderCacheRequested(u64 program_id);
void DumpRomFSRequested(u64 program_id, const std::string& game_path); void DumpRomFSRequested(u64 program_id, const std::string& game_path);
void CopyTIDRequested(u64 program_id); void CopyTIDRequested(u64 program_id);

View File

@ -1155,40 +1155,62 @@ void GMainWindow::OnGameListLoadFile(QString game_path) {
BootGame(game_path); BootGame(game_path);
} }
void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path) {
std::string path; std::string path;
QString open_target; QString open_target;
const auto v_file = Core::GetGameFileFromPath(vfs, game_path);
const auto loader = Loader::GetLoader(v_file);
FileSys::NACP control{};
u64 program_id{};
loader->ReadControlData(control);
loader->ReadProgramId(program_id);
const bool has_user_save{control.GetDefaultNormalSaveSize() > 0};
const bool has_device_save{control.GetDeviceSaveDataSize() > 0};
ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
switch (target) { switch (target) {
case GameListOpenTarget::SaveData: { case GameListOpenTarget::SaveData: {
open_target = tr("Save Data"); open_target = tr("Save Data");
const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
ASSERT(program_id != 0); ASSERT(program_id != 0);
const auto select_profile = [this] { if (has_user_save) {
QtProfileSelectionDialog dialog(this); // User save data
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | const auto select_profile = [this] {
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); QtProfileSelectionDialog dialog(this);
dialog.setWindowModality(Qt::WindowModal); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) { if (dialog.exec() == QDialog::Rejected) {
return -1; return -1;
}
return dialog.GetIndex();
};
const auto index = select_profile();
if (index == -1) {
return;
} }
return dialog.GetIndex(); Service::Account::ProfileManager manager;
}; const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
ASSERT(user_id);
const auto index = select_profile(); path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
if (index == -1) { FileSys::SaveDataSpaceId::NandUser,
return; FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0);
} else {
// Device save data
path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::SaveData, program_id, {}, 0);
} }
Service::Account::ProfileManager manager;
const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
ASSERT(user_id);
path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::SaveData,
program_id, user_id->uuid, 0);
if (!FileUtil::Exists(path)) { if (!FileUtil::Exists(path)) {
FileUtil::CreateFullPath(path); FileUtil::CreateFullPath(path);
FileUtil::CreateDir(path); FileUtil::CreateDir(path);

View File

@ -183,7 +183,7 @@ private slots:
void OnMenuReportCompatibility(); void OnMenuReportCompatibility();
/// Called whenever a user selects a game in the game list widget. /// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path); void OnGameListLoadFile(QString game_path);
void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path);
void OnTransferableShaderCacheOpenFile(u64 program_id); void OnTransferableShaderCacheOpenFile(u64 program_id);
void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
void OnGameListCopyTID(u64 program_id); void OnGameListCopyTID(u64 program_id);