diff options
| author | 2014-12-29 13:04:37 -0500 | |
|---|---|---|
| committer | 2014-12-29 22:29:55 -0500 | |
| commit | 2c89d4d5cd4e308b04cebb1c9bca48e12f0945da (patch) | |
| tree | ea0a85e43943ba76418f27a68572e8602dbd9839 /src/core/hle | |
| parent | Merge pull request #367 from bunnei/usat_ssat (diff) | |
| download | yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.tar.gz yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.tar.xz yuzu-2c89d4d5cd4e308b04cebb1c9bca48e12f0945da.zip | |
Archives: Implemented ExtSaveData and SharedExtSaveData
They will be stored in /extsavedata/SDMC and /extsavedata/NAND respectively.
Also redirect some APT_A functions to their APT_U equivalents.
Implemented the gamecoin.dat file in SharedExtSaveData in the PTM module.
Implemented formatting the savegame.
Retake a previous savegame if it exists instead of reporting them as not formatted every time a game is loaded.
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/service/apt_a.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 59 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp | 17 | ||||
| -rw-r--r-- | src/core/hle/service/ptm_u.cpp | 47 |
5 files changed, 94 insertions, 45 deletions
diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp index dcf5ec4fe..a22f5f15d 100644 --- a/src/core/hle/service/apt_a.cpp +++ b/src/core/hle/service/apt_a.cpp | |||
| @@ -6,14 +6,21 @@ | |||
| 6 | #include "core/hle/hle.h" | 6 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/service/apt_a.h" | 7 | #include "core/hle/service/apt_a.h" |
| 8 | 8 | ||
| 9 | namespace APT_U { | ||
| 10 | extern void Initialize(Service::Interface* self); | ||
| 11 | extern void GetLockHandle(Service::Interface* self); | ||
| 12 | extern void ReceiveParameter(Service::Interface* self); | ||
| 13 | extern void GlanceParameter(Service::Interface* self); | ||
| 14 | } | ||
| 15 | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // Namespace APT_A | 17 | // Namespace APT_A |
| 11 | 18 | ||
| 12 | namespace APT_A { | 19 | namespace APT_A { |
| 13 | 20 | ||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | 21 | const Interface::FunctionInfo FunctionTable[] = { |
| 15 | {0x00010040, nullptr, "GetLockHandle?"}, | 22 | {0x00010040, APT_U::GetLockHandle, "GetLockHandle?"}, |
| 16 | {0x00020080, nullptr, "Initialize?"}, | 23 | {0x00020080, APT_U::Initialize, "Initialize?"}, |
| 17 | {0x00030040, nullptr, "Enable?"}, | 24 | {0x00030040, nullptr, "Enable?"}, |
| 18 | {0x00040040, nullptr, "Finalize?"}, | 25 | {0x00040040, nullptr, "Finalize?"}, |
| 19 | {0x00050040, nullptr, "GetAppletManInfo?"}, | 26 | {0x00050040, nullptr, "GetAppletManInfo?"}, |
| @@ -22,6 +29,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 22 | {0x00430040, nullptr, "NotifyToWait?"}, | 29 | {0x00430040, nullptr, "NotifyToWait?"}, |
| 23 | {0x004B00C2, nullptr, "AppletUtility?"}, | 30 | {0x004B00C2, nullptr, "AppletUtility?"}, |
| 24 | {0x00550040, nullptr, "WriteInputToNsState?"}, | 31 | {0x00550040, nullptr, "WriteInputToNsState?"}, |
| 32 | {0x000D0080, APT_U::ReceiveParameter,"ReceiveParameter" }, | ||
| 33 | {0x000E0080, APT_U::GlanceParameter,"GlanceParameter" }, | ||
| 25 | }; | 34 | }; |
| 26 | 35 | ||
| 27 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 36 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 487bf3aa7..f19ca3a9f 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 12 | 12 | ||
| 13 | #include "core/file_sys/archive_savedata.h" | 13 | #include "core/file_sys/archive_savedata.h" |
| 14 | #include "core/file_sys/archive_extsavedata.h" | ||
| 14 | #include "core/file_sys/archive_backend.h" | 15 | #include "core/file_sys/archive_backend.h" |
| 15 | #include "core/file_sys/archive_sdmc.h" | 16 | #include "core/file_sys/archive_sdmc.h" |
| 16 | #include "core/file_sys/directory_backend.h" | 17 | #include "core/file_sys/directory_backend.h" |
| @@ -224,25 +225,20 @@ static Archive* GetArchive(ArchiveHandle handle) { | |||
| 224 | return (itr == handle_map.end()) ? nullptr : itr->second; | 225 | return (itr == handle_map.end()) ? nullptr : itr->second; |
| 225 | } | 226 | } |
| 226 | 227 | ||
| 227 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | 228 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { |
| 228 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); | 229 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); |
| 229 | 230 | ||
| 230 | auto itr = id_code_map.find(id_code); | 231 | auto itr = id_code_map.find(id_code); |
| 231 | if (itr == id_code_map.end()) { | 232 | if (itr == id_code_map.end()) { |
| 232 | if (id_code == ArchiveIdCode::SaveData) { | ||
| 233 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 234 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 235 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 236 | // with the files and folders that it expects. | ||
| 237 | // The FormatSaveData service call will create the SaveData archive when it is called. | ||
| 238 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 239 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 240 | } | ||
| 241 | // TODO: Verify error against hardware | 233 | // TODO: Verify error against hardware |
| 242 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 234 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 243 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 235 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 244 | } | 236 | } |
| 245 | 237 | ||
| 238 | ResultCode res = itr->second->backend->Open(archive_path); | ||
| 239 | if (!res.IsSuccess()) | ||
| 240 | return res; | ||
| 241 | |||
| 246 | // This should never even happen in the first place with 64-bit handles, | 242 | // This should never even happen in the first place with 64-bit handles, |
| 247 | while (handle_map.count(next_handle) != 0) { | 243 | while (handle_map.count(next_handle) != 0) { |
| 248 | ++next_handle; | 244 | ++next_handle; |
| @@ -395,25 +391,14 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||
| 395 | } | 391 | } |
| 396 | 392 | ||
| 397 | ResultCode FormatSaveData() { | 393 | ResultCode FormatSaveData() { |
| 398 | // TODO(Subv): Actually wipe the savedata folder after creating or opening it | ||
| 399 | |||
| 400 | // Do not create the archive again if it already exists | 394 | // Do not create the archive again if it already exists |
| 401 | if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end()) | 395 | auto archive_itr = id_code_map.find(ArchiveIdCode::SaveData); |
| 402 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code | 396 | if (archive_itr == id_code_map.end()) { |
| 403 | 397 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error | |
| 404 | // Create the SaveData archive | ||
| 405 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 406 | auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory, | ||
| 407 | Kernel::g_program_id); | ||
| 408 | |||
| 409 | if (savedata_archive->Initialize()) { | ||
| 410 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 411 | return RESULT_SUCCESS; | ||
| 412 | } else { | ||
| 413 | LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s", | ||
| 414 | savedata_archive->GetMountPoint().c_str()); | ||
| 415 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code | ||
| 416 | } | 398 | } |
| 399 | |||
| 400 | // Use an empty path, we do not use it when formatting the savedata | ||
| 401 | return archive_itr->second->backend->Format(FileSys::Path()); | ||
| 417 | } | 402 | } |
| 418 | 403 | ||
| 419 | /// Initialize archives | 404 | /// Initialize archives |
| @@ -430,6 +415,26 @@ void ArchiveInit() { | |||
| 430 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); | 415 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 431 | else | 416 | else |
| 432 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 417 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 418 | |||
| 419 | // Create the SaveData archive | ||
| 420 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 421 | auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory); | ||
| 422 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 423 | |||
| 424 | std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 425 | auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory); | ||
| 426 | if (extsavedata_archive->Initialize()) | ||
| 427 | CreateArchive(std::move(extsavedata_archive), ArchiveIdCode::ExtSaveData); | ||
| 428 | else | ||
| 429 | LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_directory.c_str()); | ||
| 430 | |||
| 431 | std::string sharedextsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 432 | auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sharedextsavedata_directory); | ||
| 433 | if (sharedextsavedata_archive->Initialize()) | ||
| 434 | CreateArchive(std::move(sharedextsavedata_archive), ArchiveIdCode::SharedExtSaveData); | ||
| 435 | else | ||
| 436 | LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", | ||
| 437 | sharedextsavedata_directory.c_str()); | ||
| 433 | } | 438 | } |
| 434 | 439 | ||
| 435 | /// Shutdown archives | 440 | /// Shutdown archives |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index b39bc41b6..c23b8cc46 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -29,9 +29,10 @@ typedef u64 ArchiveHandle; | |||
| 29 | /** | 29 | /** |
| 30 | * Opens an archive | 30 | * Opens an archive |
| 31 | * @param id_code IdCode of the archive to open | 31 | * @param id_code IdCode of the archive to open |
| 32 | * @param archive_path Path to the archive, used with Binary paths | ||
| 32 | * @return Handle to the opened archive | 33 | * @return Handle to the opened archive |
| 33 | */ | 34 | */ |
| 34 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code); | 35 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path); |
| 35 | 36 | ||
| 36 | /** | 37 | /** |
| 37 | * Closes an archive | 38 | * Closes an archive |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index b1a465274..7eb32146d 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -107,14 +107,7 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 107 | LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", | 107 | LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", |
| 108 | archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); | 108 | archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); |
| 109 | 109 | ||
| 110 | if (archive_path.GetType() != FileSys::Empty) { | 110 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); |
| 111 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||
| 112 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 113 | cmd_buff[3] = 0; | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id); | ||
| 118 | if (archive_handle.Failed()) { | 111 | if (archive_handle.Failed()) { |
| 119 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 112 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 120 | cmd_buff[1] = archive_handle.Code().raw; | 113 | cmd_buff[1] = archive_handle.Code().raw; |
| @@ -376,13 +369,7 @@ static void OpenArchive(Service::Interface* self) { | |||
| 376 | 369 | ||
| 377 | LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); | 370 | LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); |
| 378 | 371 | ||
| 379 | if (archive_path.GetType() != FileSys::Empty) { | 372 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path); |
| 380 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | ||
| 381 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | |||
| 385 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id); | ||
| 386 | cmd_buff[1] = handle.Code().raw; | 373 | cmd_buff[1] = handle.Code().raw; |
| 387 | if (handle.Succeeded()) { | 374 | if (handle.Succeeded()) { |
| 388 | cmd_buff[2] = *handle & 0xFFFFFFFF; | 375 | cmd_buff[2] = *handle & 0xFFFFFFFF; |
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp index d1498f05c..9cc700c46 100644 --- a/src/core/hle/service/ptm_u.cpp +++ b/src/core/hle/service/ptm_u.cpp | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/log.h" | 5 | #include "common/log.h" |
| 6 | #include "common/make_unique.h" | ||
| 7 | #include "core/file_sys/archive_extsavedata.h" | ||
| 6 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/service/ptm_u.h" | 9 | #include "core/hle/service/ptm_u.h" |
| 8 | 10 | ||
| @@ -11,6 +13,24 @@ | |||
| 11 | 13 | ||
| 12 | namespace PTM_U { | 14 | namespace PTM_U { |
| 13 | 15 | ||
| 16 | /** | ||
| 17 | * Represents the gamecoin file structure in the SharedExtData archive | ||
| 18 | * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) | ||
| 19 | */ | ||
| 20 | struct GameCoin { | ||
| 21 | u32 magic; ///< Magic number: 0x4F00 | ||
| 22 | u16 total_coins; ///< Total Play Coins | ||
| 23 | u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. | ||
| 24 | u32 step_count; ///< Total step count at the time a new Play Coin was obtained. | ||
| 25 | u32 last_step_count; ///< Step count for the day the last Play Coin was obtained | ||
| 26 | u16 year; | ||
| 27 | u8 month; | ||
| 28 | u8 day; | ||
| 29 | }; | ||
| 30 | static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; | ||
| 31 | static std::unique_ptr<FileSys::Archive_ExtSaveData> ptm_shared_extsavedata; | ||
| 32 | static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; | ||
| 33 | |||
| 14 | /// Charge levels used by PTM functions | 34 | /// Charge levels used by PTM functions |
| 15 | enum class ChargeLevels : u32 { | 35 | enum class ChargeLevels : u32 { |
| 16 | CriticalBattery = 1, | 36 | CriticalBattery = 1, |
| @@ -120,6 +140,33 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 120 | 140 | ||
| 121 | Interface::Interface() { | 141 | Interface::Interface() { |
| 122 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 142 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 143 | // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file | ||
| 144 | // TODO(Subv): In the future we should use the FS service to query this archive | ||
| 145 | std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA); | ||
| 146 | ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory); | ||
| 147 | if (!ptm_shared_extsavedata->Initialize()) { | ||
| 148 | LOG_CRITICAL(Service_PTM, "Could not initialize ExtSaveData archive for the PTM:U service"); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | FileSys::Path archive_path(ptm_shared_extdata_id); | ||
| 152 | ResultCode result = ptm_shared_extsavedata->Open(archive_path); | ||
| 153 | // If the archive didn't exist, create the files inside | ||
| 154 | if (result.description == ErrorDescription::FS_NotFormatted) { | ||
| 155 | // Format the archive to clear the directories | ||
| 156 | ptm_shared_extsavedata->Format(archive_path); | ||
| 157 | // Open it again to get a valid archive now that the folder exists | ||
| 158 | ptm_shared_extsavedata->Open(archive_path); | ||
| 159 | FileSys::Path gamecoin_path("gamecoin.dat"); | ||
| 160 | FileSys::Mode open_mode = {}; | ||
| 161 | open_mode.write_flag = 1; | ||
| 162 | open_mode.create_flag = 1; | ||
| 163 | // Open the file and write the default gamecoin information | ||
| 164 | auto gamecoin = ptm_shared_extsavedata->OpenFile(gamecoin_path, open_mode); | ||
| 165 | if (gamecoin != nullptr) { | ||
| 166 | gamecoin->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); | ||
| 167 | gamecoin->Close(); | ||
| 168 | } | ||
| 169 | } | ||
| 123 | } | 170 | } |
| 124 | 171 | ||
| 125 | } // namespace | 172 | } // namespace |