mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Artic Base: Implement DLC support and other fixes (#173)
* Artic Base: Implement DLC support and other fixes * Fix per game settings not working with artic loader * Fix compilation error
This commit is contained in:
		
							parent
							
								
									1e2be72e5e
								
							
						
					
					
						commit
						4780a7134d
					
				
					 16 changed files with 992 additions and 236 deletions
				
			
		|  | @ -151,7 +151,14 @@ void ConfigurePerGame::LoadConfiguration() { | |||
|     ui->display_title_id->setText( | ||||
|         QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper()); | ||||
| 
 | ||||
|     const auto loader = Loader::GetLoader(filename); | ||||
|     std::unique_ptr<Loader::AppLoader> loader_ptr; | ||||
|     Loader::AppLoader* loader; | ||||
|     if (system.IsPoweredOn()) { | ||||
|         loader = &system.GetAppLoader(); | ||||
|     } else { | ||||
|         loader_ptr = Loader::GetLoader(filename); | ||||
|         loader = loader_ptr.get(); | ||||
|     } | ||||
| 
 | ||||
|     std::string title; | ||||
|     if (loader->ReadTitle(title) == Loader::ResultStatus::Success) | ||||
|  |  | |||
|  | @ -1216,7 +1216,10 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
|         case Core::System::ResultStatus::ErrorArticDisconnected: | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Artic Base Server"), | ||||
|                 tr("An error has occurred whilst communicating with the Artic Base Server.")); | ||||
|                 tr(fmt::format( | ||||
|                        "An error has occurred whilst communicating with the Artic Base Server.\n{}", | ||||
|                        system.GetStatusDetails()) | ||||
|                        .c_str())); | ||||
|             break; | ||||
|         default: | ||||
|             QMessageBox::critical( | ||||
|  | @ -1238,6 +1241,10 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| } | ||||
| 
 | ||||
| void GMainWindow::BootGame(const QString& filename) { | ||||
|     if (emu_thread) { | ||||
|         ShutdownGame(); | ||||
|     } | ||||
| 
 | ||||
|     const bool is_artic = filename.startsWith(QString::fromStdString("articbase://")); | ||||
| 
 | ||||
|     if (!is_artic && filename.endsWith(QStringLiteral(".cia"))) { | ||||
|  | @ -2640,10 +2647,12 @@ void GMainWindow::UpdateStatusBar() { | |||
|         const bool do_mb = results.artic_transmitted >= (1000.0 * 1000.0); | ||||
|         const double value = do_mb ? (results.artic_transmitted / (1000.0 * 1000.0)) | ||||
|                                    : (results.artic_transmitted / 1000.0); | ||||
|         static const std::array<std::pair<Core::PerfStats::PerfArticEventBits, QString>, 4> | ||||
|         static const std::array<std::pair<Core::PerfStats::PerfArticEventBits, QString>, 5> | ||||
|             perf_events = { | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SHARED_EXT_DATA, | ||||
|                                tr("(Accessing SharedExtData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_SYSTEM_SAVE_DATA, | ||||
|                                tr("(Accessing SystemSaveData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_BOSS_EXT_DATA, | ||||
|                                tr("(Accessing BossExtData)")), | ||||
|                 std::make_pair(Core::PerfStats::PerfArticEventBits::ARTIC_EXT_DATA, | ||||
|  | @ -2868,7 +2877,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det | |||
|         error_severity_icon = QMessageBox::Icon::Warning; | ||||
|     } else if (result == Core::System::ResultStatus::ErrorArticDisconnected) { | ||||
|         title = tr("Artic Base Server"); | ||||
|         message = tr("A communication error has occurred. The game will quit."); | ||||
|         message = | ||||
|             tr(fmt::format("A communication error has occurred. The game will quit.\n{}", details) | ||||
|                    .c_str()); | ||||
|         error_severity_icon = QMessageBox::Icon::Critical; | ||||
|         can_continue = false; | ||||
|     } else { | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include "common/archives.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/file_util.h" | ||||
| #include "core/file_sys/archive_artic.h" | ||||
| #include "core/file_sys/archive_systemsavedata.h" | ||||
| #include "core/file_sys/errors.h" | ||||
| #include "core/file_sys/savedata_archive.h" | ||||
|  | @ -52,24 +53,45 @@ Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) { | |||
| ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) | ||||
|     : base_path(GetSystemSaveDataContainerPath(nand_path)) {} | ||||
| 
 | ||||
| static bool AllowArticSystemSaveData(const Path& path) { | ||||
|     constexpr u32 APP_SYSTEM_SAVE_DATA_MASK = 0x00020000; | ||||
|     if (path.GetType() == FileSys::LowPathType::Binary) { | ||||
|         std::vector<u8> path_data = path.AsBinary(); | ||||
|         return path_data.size() == 8 && | ||||
|                (*reinterpret_cast<u32*>(path_data.data() + 4) & APP_SYSTEM_SAVE_DATA_MASK) != 0; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(const Path& path, | ||||
|                                                                                u64 program_id) { | ||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::Exists(fullpath)) { | ||||
|         // TODO(Subv): Check error code, this one is probably wrong
 | ||||
|         return ResultNotFound; | ||||
|     if (IsUsingArtic() && AllowArticSystemSaveData(path)) { | ||||
|         EnsureCacheCreated(); | ||||
|         return ArticArchive::Open(artic_client, Service::FS::ArchiveIdCode::SystemSaveData, path, | ||||
|                                   Core::PerfStats::PerfArticEventBits::ARTIC_SYSTEM_SAVE_DATA, | ||||
|                                   *this, false); | ||||
|     } else { | ||||
|         std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|         if (!FileUtil::Exists(fullpath)) { | ||||
|             // TODO(Subv): Check error code, this one is probably wrong
 | ||||
|             return ResultNotFound; | ||||
|         } | ||||
|         return std::make_unique<SaveDataArchive>(fullpath); | ||||
|     } | ||||
|     return std::make_unique<SaveDataArchive>(fullpath); | ||||
| } | ||||
| 
 | ||||
| Result ArchiveFactory_SystemSaveData::Format(const Path& path, | ||||
|                                              const FileSys::ArchiveFormatInfo& format_info, | ||||
|                                              u64 program_id, u32 directory_buckets, | ||||
|                                              u32 file_buckets) { | ||||
|     std::string fullpath = GetSystemSaveDataPath(base_path, path); | ||||
|     FileUtil::DeleteDirRecursively(fullpath); | ||||
|     FileUtil::CreateFullPath(fullpath); | ||||
|     return ResultSuccess; | ||||
|     const std::vector<u8> vec_data = path.AsBinary(); | ||||
|     u32 save_low; | ||||
|     u32 save_high; | ||||
|     std::memcpy(&save_low, &vec_data[4], sizeof(u32)); | ||||
|     std::memcpy(&save_high, &vec_data[0], sizeof(u32)); | ||||
|     return FormatAsSysData(save_high, save_low, format_info.total_size, 0x1000, | ||||
|                            format_info.number_directories, format_info.number_files, | ||||
|                            directory_buckets, file_buckets, format_info.duplicate_data); | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path, | ||||
|  | @ -79,4 +101,45 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const | |||
|     return ResultUnknown; | ||||
| } | ||||
| 
 | ||||
| Result ArchiveFactory_SystemSaveData::FormatAsSysData(u32 high, u32 low, u32 total_size, | ||||
|                                                       u32 block_size, u32 number_directories, | ||||
|                                                       u32 number_files, | ||||
|                                                       u32 number_directory_buckets, | ||||
|                                                       u32 number_file_buckets, u8 duplicate_data) { | ||||
|     if (IsUsingArtic() && | ||||
|         AllowArticSystemSaveData(FileSys::ConstructSystemSaveDataBinaryPath(high, low))) { | ||||
|         auto req = artic_client->NewRequest("FSUSER_CreateSysSaveData"); | ||||
| 
 | ||||
|         req.AddParameterU32(high); | ||||
|         req.AddParameterU32(low); | ||||
|         req.AddParameterU32(total_size); | ||||
|         req.AddParameterU32(block_size); | ||||
|         req.AddParameterU32(number_directories); | ||||
|         req.AddParameterU32(number_files); | ||||
|         req.AddParameterU32(number_directory_buckets); | ||||
|         req.AddParameterU32(number_file_buckets); | ||||
|         req.AddParameterU8(duplicate_data); | ||||
| 
 | ||||
|         auto resp = artic_client->Send(req); | ||||
|         if (!resp.has_value() || !resp->Succeeded()) { | ||||
|             return ResultUnknown; | ||||
|         } | ||||
| 
 | ||||
|         Result res(static_cast<u32>(resp->GetMethodResult())); | ||||
|         return res; | ||||
| 
 | ||||
|     } else { | ||||
|         // Construct the binary path to the archive first
 | ||||
|         const FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||
| 
 | ||||
|         const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | ||||
|         const std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); | ||||
|         const std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); | ||||
|         if (!FileUtil::CreateFullPath(systemsavedata_path)) { | ||||
|             return ResultUnknown; // TODO(Subv): Find the right error code
 | ||||
|         } | ||||
|         return ResultSuccess; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
|  |  | |||
|  | @ -10,12 +10,15 @@ | |||
| #include <boost/serialization/string.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "core/file_sys/archive_backend.h" | ||||
| #include "core/file_sys/artic_cache.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "network/artic_base/artic_base_client.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| /// File system interface to the SystemSaveData archive
 | ||||
| class ArchiveFactory_SystemSaveData final : public ArchiveFactory { | ||||
| class ArchiveFactory_SystemSaveData final : public ArchiveFactory, public ArticCacheProvider { | ||||
| public: | ||||
|     explicit ArchiveFactory_SystemSaveData(const std::string& mount_point); | ||||
| 
 | ||||
|  | @ -24,13 +27,31 @@ public: | |||
|                   u32 directory_buckets, u32 file_buckets) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override; | ||||
| 
 | ||||
|     Result FormatAsSysData(u32 high, u32 low, u32 total_size, u32 block_size, | ||||
|                            u32 number_directories, u32 number_files, u32 number_directory_buckets, | ||||
|                            u32 number_file_buckets, u8 duplicate_data); | ||||
| 
 | ||||
|     std::string GetName() const override { | ||||
|         return "SystemSaveData"; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSlow() override { | ||||
|         return IsUsingArtic(); | ||||
|     } | ||||
| 
 | ||||
|     void RegisterArtic(std::shared_ptr<Network::ArticBase::Client>& client) { | ||||
|         artic_client = client; | ||||
|     } | ||||
| 
 | ||||
|     bool IsUsingArtic() const { | ||||
|         return artic_client.get() != nullptr; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::string base_path; | ||||
| 
 | ||||
|     std::shared_ptr<Network::ArticBase::Client> artic_client = nullptr; | ||||
| 
 | ||||
|     ArchiveFactory_SystemSaveData() = default; | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int) { | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -20,6 +20,7 @@ | |||
| #include "core/hle/kernel/mutex.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "network/artic_base/artic_base_client.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
|  | @ -245,7 +246,13 @@ public: | |||
|             return am; | ||||
|         } | ||||
| 
 | ||||
|         void UseArticClient(std::shared_ptr<Network::ArticBase::Client>& client) { | ||||
|             artic_client = client; | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         void GetProgramInfosImpl(Kernel::HLERequestContext& ctx, bool ignore_platform); | ||||
| 
 | ||||
|         /**
 | ||||
|          * AM::GetNumPrograms service function | ||||
|          * Gets the number of installed titles in the requested media type | ||||
|  | @ -753,6 +760,9 @@ public: | |||
| 
 | ||||
|     protected: | ||||
|         std::shared_ptr<Module> am; | ||||
| 
 | ||||
|         // Placed on the interface level so that only am:net and am:app have it.
 | ||||
|         std::shared_ptr<Network::ArticBase::Client> artic_client = nullptr; | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|  |  | |||
|  | @ -278,7 +278,7 @@ void Module::Interface::GetTransferableId(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
|     std::array<u8, 12> buffer; | ||||
|     const Result result = | ||||
|         cfg->GetConfigBlock(ConsoleUniqueID2BlockID, 8, AccessFlag::SystemRead, buffer.data()); | ||||
|         cfg->GetConfigBlock(ConsoleUniqueID2BlockID, 8, AccessFlag::Global, buffer.data()); | ||||
|     rb.Push(result); | ||||
|     if (result.IsSuccess()) { | ||||
|         std::memcpy(&buffer[8], &app_id_salt, sizeof(u32)); | ||||
|  | @ -502,11 +502,42 @@ ResultVal<void*> Module::GetConfigBlockPointer(u32 block_id, u32 size, AccessFla | |||
| } | ||||
| 
 | ||||
| Result Module::GetConfigBlock(u32 block_id, u32 size, AccessFlag accesss_flag, void* output) { | ||||
|     void* pointer = nullptr; | ||||
|     CASCADE_RESULT(pointer, GetConfigBlockPointer(block_id, size, accesss_flag)); | ||||
|     std::memcpy(output, pointer, size); | ||||
|     bool get_from_artic = | ||||
|         block_id == ConsoleUniqueID2BlockID && | ||||
|         (static_cast<u16>(accesss_flag) & static_cast<u16>(AccessFlag::UserRead)) != 0; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
|     if (get_from_artic && artic_client.get()) { | ||||
|         auto req = artic_client->NewRequest("CFGU_GetConfigInfoBlk2"); | ||||
| 
 | ||||
|         req.AddParameterS32(block_id); | ||||
|         req.AddParameterU32(size); | ||||
| 
 | ||||
|         auto resp = artic_client->Send(req); | ||||
| 
 | ||||
|         if (!resp.has_value() || !resp->Succeeded()) | ||||
|             return Result(-1); | ||||
| 
 | ||||
|         auto res = Result(static_cast<u32>(resp->GetMethodResult())); | ||||
|         if (res.IsError()) | ||||
|             return res; | ||||
| 
 | ||||
|         auto buff = resp->GetResponseBuffer(0); | ||||
|         if (!buff.has_value()) | ||||
|             return Result(-1); | ||||
|         size_t actually_read = buff->second; | ||||
|         if (actually_read > size) | ||||
|             return Result(-1); | ||||
| 
 | ||||
|         memcpy(output, buff->first, actually_read); | ||||
|         return ResultSuccess; | ||||
| 
 | ||||
|     } else { | ||||
|         void* pointer = nullptr; | ||||
|         CASCADE_RESULT(pointer, GetConfigBlockPointer(block_id, size, accesss_flag)); | ||||
|         std::memcpy(output, pointer, size); | ||||
| 
 | ||||
|         return ResultSuccess; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Result Module::SetConfigBlock(u32 block_id, u32 size, AccessFlag accesss_flag, const void* input) { | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include <utility> | ||||
| #include "common/common_types.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "network/artic_base/artic_base_client.h" | ||||
| 
 | ||||
| namespace FileSys { | ||||
| class ArchiveBackend; | ||||
|  | @ -210,6 +211,10 @@ public: | |||
| 
 | ||||
|         std::shared_ptr<Module> GetModule() const; | ||||
| 
 | ||||
|         void UseArticClient(std::shared_ptr<Network::ArticBase::Client>& client) { | ||||
|             GetModule()->artic_client = client; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * CFG::GetCountryCodeString service function | ||||
|          *  Inputs: | ||||
|  | @ -680,6 +685,8 @@ private: | |||
|     bool preferred_region_chosen = false; | ||||
|     MCUData mcu_data{}; | ||||
| 
 | ||||
|     std::shared_ptr<Network::ArticBase::Client> artic_client = nullptr; | ||||
| 
 | ||||
|     template <class Archive> | ||||
|     void serialize(Archive& ar, const unsigned int); | ||||
|     friend class boost::serialization::access; | ||||
|  |  | |||
|  | @ -298,18 +298,22 @@ Result ArchiveManager::DeleteSystemSaveData(u32 high, u32 low) { | |||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result ArchiveManager::CreateSystemSaveData(u32 high, u32 low) { | ||||
|     // Construct the binary path to the archive first
 | ||||
|     const FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||
| Result ArchiveManager::CreateSystemSaveData(u32 high, u32 low, u32 total_size, u32 block_size, | ||||
|                                             u32 number_directories, u32 number_files, | ||||
|                                             u32 number_directory_buckets, u32 number_file_buckets, | ||||
|                                             u8 duplicate_data) { | ||||
| 
 | ||||
|     const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | ||||
|     const std::string base_path = FileSys::GetSystemSaveDataContainerPath(nand_directory); | ||||
|     const std::string systemsavedata_path = FileSys::GetSystemSaveDataPath(base_path, path); | ||||
|     if (!FileUtil::CreateFullPath(systemsavedata_path)) { | ||||
|         return ResultUnknown; // TODO(Subv): Find the right error code
 | ||||
|     auto archive = id_code_map.find(ArchiveIdCode::SystemSaveData); | ||||
| 
 | ||||
|     if (archive == id_code_map.end()) { | ||||
|         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||
|     } | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
|     auto sys_savedata = static_cast<FileSys::ArchiveFactory_SystemSaveData*>(archive->second.get()); | ||||
| 
 | ||||
|     return sys_savedata->FormatAsSysData(high, low, total_size, block_size, number_directories, | ||||
|                                          number_files, number_directory_buckets, | ||||
|                                          number_file_buckets, duplicate_data); | ||||
| } | ||||
| 
 | ||||
| ResultVal<ArchiveResource> ArchiveManager::GetArchiveResource(MediaType media_type) const { | ||||
|  | @ -454,6 +458,16 @@ void ArchiveManager::RegisterArticNCCH(std::shared_ptr<Network::ArticBase::Clien | |||
|     reinterpret_cast<FileSys::ArchiveFactory_NCCH*>(itr->second.get())->RegisterArtic(client); | ||||
| } | ||||
| 
 | ||||
| void ArchiveManager::RegisterArticSystemSaveData( | ||||
|     std::shared_ptr<Network::ArticBase::Client>& client) { | ||||
|     auto itr = id_code_map.find(ArchiveIdCode::SystemSaveData); | ||||
|     if (itr == id_code_map.end() || itr->second.get() == nullptr) { | ||||
|         return; | ||||
|     } | ||||
|     reinterpret_cast<FileSys::ArchiveFactory_SystemSaveData*>(itr->second.get()) | ||||
|         ->RegisterArtic(client); | ||||
| } | ||||
| 
 | ||||
| ArchiveManager::ArchiveManager(Core::System& system) : system(system) { | ||||
|     RegisterArchiveTypes(); | ||||
| } | ||||
|  |  | |||
|  | @ -264,11 +264,12 @@ public: | |||
| 
 | ||||
|     /**
 | ||||
|      * Creates the SystemSaveData archive folder for the specified save data id | ||||
|      * @param high The high word of the SystemSaveData archive to create | ||||
|      * @param low The low word of the SystemSaveData archive to create | ||||
|      * @return Result 0 on success or the corresponding code on error | ||||
|      */ | ||||
|     Result CreateSystemSaveData(u32 high, u32 low); | ||||
|     Result CreateSystemSaveData(u32 high, u32 low, u32 total_size, u32 block_size, | ||||
|                                 u32 number_directories, u32 number_files, | ||||
|                                 u32 number_directory_buckets, u32 number_file_buckets, | ||||
|                                 u8 duplicate_data); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns capacity and free space information about the given media type. | ||||
|  | @ -296,6 +297,8 @@ public: | |||
| 
 | ||||
|     void RegisterArticNCCH(std::shared_ptr<Network::ArticBase::Client>& client); | ||||
| 
 | ||||
|     void RegisterArticSystemSaveData(std::shared_ptr<Network::ArticBase::Client>& client); | ||||
| 
 | ||||
| private: | ||||
|     Core::System& system; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1026,7 +1026,9 @@ void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) { | |||
|         file_buckets, duplicate); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     rb.Push(archives.CreateSystemSaveData(savedata_high, savedata_low)); | ||||
|     rb.Push(archives.CreateSystemSaveData(savedata_high, savedata_low, total_size, block_size, | ||||
|                                           directories, files, directory_buckets, file_buckets, | ||||
|                                           duplicate ? 1 : 0)); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) { | ||||
|  | @ -1048,7 +1050,8 @@ void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|     // With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND)
 | ||||
|     rb.Push(archives.CreateSystemSaveData(0, savedata_id)); | ||||
|     rb.Push(archives.CreateSystemSaveData(0, savedata_id, total_size, block_size, directories, | ||||
|                                           files, directory_buckets, file_buckets, duplicate)); | ||||
| } | ||||
| 
 | ||||
| void FS_USER::InitializeWithSdkVersion(Kernel::HLERequestContext& ctx) { | ||||
|  |  | |||
|  | @ -21,7 +21,10 @@ | |||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/am/am.h" | ||||
| #include "core/hle/service/am/am_app.h" | ||||
| #include "core/hle/service/am/am_net.h" | ||||
| #include "core/hle/service/cfg/cfg.h" | ||||
| #include "core/hle/service/cfg/cfg_u.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| #include "core/hle/service/fs/fs_user.h" | ||||
| #include "core/loader/artic.h" | ||||
|  | @ -335,9 +338,28 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) { | |||
|     system.ArchiveManager().RegisterArticSaveDataSource(client); | ||||
|     system.ArchiveManager().RegisterArticExtData(client); | ||||
|     system.ArchiveManager().RegisterArticNCCH(client); | ||||
|     system.ArchiveManager().RegisterArticSystemSaveData(client); | ||||
| 
 | ||||
|     auto fs_user = system.ServiceManager().GetService<Service::FS::FS_USER>("fs:USER"); | ||||
|     fs_user->RegisterSecureValueBackend(std::make_shared<FileSys::ArticSecureValueBackend>(client)); | ||||
|     if (fs_user.get()) { | ||||
|         fs_user->RegisterSecureValueBackend( | ||||
|             std::make_shared<FileSys::ArticSecureValueBackend>(client)); | ||||
|     } | ||||
| 
 | ||||
|     auto cfg = system.ServiceManager().GetService<Service::CFG::CFG_U>("cfg:u"); | ||||
|     if (cfg.get()) { | ||||
|         cfg->UseArticClient(client); | ||||
|     } | ||||
| 
 | ||||
|     auto amnet = system.ServiceManager().GetService<Service::AM::AM_NET>("am:net"); | ||||
|     if (amnet.get()) { | ||||
|         amnet->UseArticClient(client); | ||||
|     } | ||||
| 
 | ||||
|     auto amapp = system.ServiceManager().GetService<Service::AM::AM_APP>("am:app"); | ||||
|     if (amapp.get()) { | ||||
|         amapp->UseArticClient(client); | ||||
|     } | ||||
| 
 | ||||
|     ParseRegionLockoutInfo(ncch_program_id); | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,8 +21,9 @@ public: | |||
|     Apploader_Artic(Core::System& system_, const std::string& server_addr, u16 server_port) | ||||
|         : AppLoader(system_, FileUtil::IOFile()) { | ||||
|         client = std::make_shared<Network::ArticBase::Client>(server_addr, server_port); | ||||
|         client->SetCommunicationErrorCallback([&system_]() { | ||||
|             system_.SetStatus(Core::System::ResultStatus::ErrorArticDisconnected); | ||||
|         client->SetCommunicationErrorCallback([&system_](const std::string& msg) { | ||||
|             system_.SetStatus(Core::System::ResultStatus::ErrorArticDisconnected, | ||||
|                               msg.empty() ? nullptr : msg.c_str()); | ||||
|         }); | ||||
|         client->SetArticReportTrafficCallback( | ||||
|             [&system_](u32 bytes) { system_.ReportArticTraffic(bytes); }); | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ public: | |||
|         ARTIC_EXT_DATA = (1 << 1), | ||||
|         ARTIC_BOSS_EXT_DATA = (1 << 2), | ||||
|         ARTIC_SHARED_EXT_DATA = (1 << 3), | ||||
|         ARTIC_SYSTEM_SAVE_DATA = (1 << 4), | ||||
|     }; | ||||
|     union PerfArticEvents { | ||||
|         u32 raw{}; | ||||
|  |  | |||
|  | @ -197,7 +197,8 @@ bool Client::Connect() { | |||
|             shutdown(main_socket, SHUT_RDWR); | ||||
|             closesocket(main_socket); | ||||
|             LOG_ERROR(Network, "Incompatible server version: {}", version_value); | ||||
|             SignalCommunicationError(); | ||||
|             SignalCommunicationError("\nIncompatible Artic Base Server version.\nCheck for updates " | ||||
|                                      "to Artic Base Server or Citra."); | ||||
|             return false; | ||||
|         } | ||||
|     } else { | ||||
|  | @ -369,11 +370,11 @@ std::optional<Client::Response> Client::Send(Request& request) { | |||
|     return std::optional<Client::Response>(std::move(resp.response)); | ||||
| } | ||||
| 
 | ||||
| void Client::SignalCommunicationError() { | ||||
| void Client::SignalCommunicationError(const std::string& msg) { | ||||
|     StopImpl(true); | ||||
|     LOG_CRITICAL(Network, "Communication error"); | ||||
|     if (communication_error_callback) | ||||
|         communication_error_callback(); | ||||
|         communication_error_callback(msg); | ||||
| } | ||||
| 
 | ||||
| void Client::PingFunction() { | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ public: | |||
|         StopImpl(false); | ||||
|     } | ||||
| 
 | ||||
|     void SetCommunicationErrorCallback(const std::function<void()>& callback) { | ||||
|     void SetCommunicationErrorCallback(const std::function<void(const std::string&)>& callback) { | ||||
|         communication_error_callback = callback; | ||||
|     } | ||||
| 
 | ||||
|  | @ -98,7 +98,7 @@ public: | |||
|     } | ||||
| 
 | ||||
| private: | ||||
|     static constexpr const int SERVER_VERSION = 0; | ||||
|     static constexpr const int SERVER_VERSION = 1; | ||||
| 
 | ||||
|     std::string address; | ||||
|     u16 port; | ||||
|  | @ -109,8 +109,8 @@ private: | |||
|         return currRequestID++; | ||||
|     } | ||||
| 
 | ||||
|     void SignalCommunicationError(); | ||||
|     std::function<void()> communication_error_callback; | ||||
|     void SignalCommunicationError(const std::string& msg = ""); | ||||
|     std::function<void(const std::string&)> communication_error_callback; | ||||
| 
 | ||||
|     std::function<void(u64)> report_artic_event_callback; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue